 Thank you very much. Thanks for coming to DjangoCon. Wonderful speakers here. I hope I can move up to the podium. Now, I generally speak about security in the Django meetup in New York. And my first time I did this, I spoke for about three hours, and I realized that maybe I should tone down the slides a little bit. And these days, I largely speak about attacks, but when it came to posting content for DjangoCon, I figured let's not look at attacks, attacks change. Also, there's a video. I don't want someone learning the wrong things from this talk. So I've come up with a little bit of a unique approach to how we're going to go through security. So I'm employed by a wonderful company called Genesis. I used to be employed by a company called Manasano. How many of you have heard of Manasano? How many have done the crypto challenges? OK, good. So at least you have some people. I did web application penetration testing for about two years. Moved over to Genesis to do it more, to own security in-house. And I like to stay employed. So I'd like to mention that the contents of these slides are my own. Now, when it comes to speaking about security, it gets really tough. Everyone, you're always taught about security. They drag you into a big conference room in these large corporations if you work in one of those. Or in a small place, and you hear about it, you read about it on Hacker News and on Reddit, about different hacks. And it's a hard problem. It still exists. And one of the major reasons for that is that your app or your app ecosystem is only secured as its lowest common denominator. Take Google, for example. It's one cross-site scripting bug within one Google app. It affects every single Google app because they implicitly trust each other. Now, that's really tough because the surface gets really, really big. Also, security is constantly changing. What was good yesterday is not good today. And as a caveat, these slides work for today. They'll probably work a little bit more, but you should take these points down, research them further, because they may change. So let's look at what we can do to change that. Now, if you want to break down security vulnerabilities into two categories, they can be broken down rather simply. There's either a lack of or improperly designed and properly coded security controls. And these will cause you to be vulnerable to attacks like denial of service and where you don't have great limiting authentication bypass because your authentication mechanism isn't secure or is susceptible to bypass. And then the worst and most common is improperly implemented cryptographic primitives, which you're encrypting the data to data looks encrypted but can easily be decrypted or can be modified. And then there is mixing data up with code and these largely run around with the remote code execution vulnerabilities. Now, while there are obviously there applications that have remote code execution interfaces built into them, stuff like SQL injection and cross-site scripting in where an attacker can make their data execute as code on your server or at least within the context of cross-site scripting within the client's browser, largely involves the data and code being mixed up. So let's look at these things in a little bit of a different way, right? So as opposed to looking how to prevent the attacks, let's look to build our software to be more robust. Let's not look how we're being attacked. Let's look to build better software. Now, every language, every program has side effects, but there are side effects that we can prevent. And I feel that one of the first things in making a more secure program is building software that is incredibly assertive. You must, to the best of your ability, assert as much as possible what the user is giving you is what you intend it to be. Not what you think it's going to be, what you intended. And that's very important. And the Python Zen has this, where it says explicit is better than implicit. Don't just take the input from the user, assert it, make sure it's exactly what you want. Now, let's look at the easy one, which is mixing code and data. And when we talk about mitigating cross-site scripting and SQL injection, we talk about statements like output encoding or prepared statements to parameterize queries. And these statements sound very nice. And when you get hit by a cross-site scripting logo, they tell you, oh, you have to output in code and you have to, or when you get hit by SQL injection, they'll tell you, you have to use parameterized queries, prepared statements, but these are stop-gap measures. Let's look at what these things actually are. So when we get hit by this bug, for example, let's say SQL injection, we have a SQL query. We've got data from the user. Now, do you know what that data is? Well, let's say it's supposed to be a number. Let's say it's supposed to be text. Now, it should only be text and it should only be considered text by our SQL server. So if we explicitly put it into that category, at that point, we've mitigated it. And that's what prepared statements are. Prepared statements are parameterized queries. They're called both things. That's why I keep on using both of them because literally in each app ecosystem, they have another way of saying prepared statements are parameterized queries. But they mark, they explicitly tell the SQL parser, this is data, do not execute this. Insert this when you need the data required in this location. You explicitly mark that as data. When it comes to output encoding, when you're reflecting user data on the page, at that point, you have the ability to, you're marking that user data. You're marking that user text or user bytes as data. You're telling the HTML parser, you're telling the JavaScript engine within your browser not to execute that. Now, this should be a general rule. And this is one that I follow and that I feel that many of you should follow as well. Be assertive. If you don't know what it is, find out where it's going to be used. And whatever you do, you will not get heard if you mark it as data. Like marking it as code is a risky option. Try not to go in the risky side. Now, let's look at the security controls. So this is where it gets really tough because security controls, you have to understand attack surfaces. You have to understand threat modeling. You have to be able to build your security controls in a robust way. And that's tough because the current security controls that we all use every day have been a cumulative set of knowledge or research around the security controls. And we've only gotten to this point because of all the attacks that they've been hit by. We only have security controls because we need them. We don't have them because it was an initial thought. Security is always an afterthought. It's only after an attacker comes. If a bank didn't need a vault, they would not invest money in a vault, but they need one. And then as the vaults have been broken into, so too the vault technology has evolved. So what's really important to notice if you're going to ever build security controls, if you're going to ever implement them or use them, use popular ones. What I mean by popular is use ones that industry leaders use. You can find strength in numbers, right? Do not use one that one or two people use. There are many times I will go online on GitHub and see a new model that's great and has awesome functionality and contains an authentication bypass or contains a security bug that you've now opened that unsuspecting users actually gonna just jump straight into. And the way these holes are mitigated, the way that these holes are patched up to the more people using them, the more people reviewing the code and therefore building out and helping build a better security control. Now, Django helps us with authentication. It doesn't help us very much with authorization. So a lot of us find ourselves writing authorization code. It's really important that when you build this code, these authorization views or authorization decorators, that you build them, you write them in one, you put them in one place. They should not be scattered amongst your application. It's literally, you can take the Python Zen, read it 10 times before writing any security control. If finding, having them broken up into many different locations can lead to a vulnerability, especially when you intend to update or mitigate a specific attack. And now you have to do it in every single location. Now, again, as mentioned previously with our data and code example, it's really important to be explicit. But conservative, I'll explain why a little bit later. Now, if you find yourself in the case where you have to actually build, let's say a login system, at that point, you need to literally go by the book. You need to get a web application, a security book, a good one and a high recommendations later on, and you need to go down the list of all the attacks and find out how they're mitigated. You need to look at current secure, or at least secure as of today or now, or at least we hope so, login systems and design yours to be very similar, if not the same. You must understand the attacks and whatever you do, do not write your own crypto routines. I have so much pain on the internet when I see large organizations and you get how blinking to very insecure crypto routines. Now, it's also important to note that you have to understand what you're doing. So, you have to be very conservative in using cryptographic hash functions, and we'll get to this a little bit later. But most of all, what's really, really important is Django provides very good and very powerful security routines. It's important that you use them because this is what the strength in numbers mean. Django is popular, we're all here, we all represent that community. There are many of us, no, many in that community that are not here today. I think we probably feel more than this hotel, if no. So, Django is very popular, if Django implements it, you should be implementing it. Now, let's look at some security controls that Django provides, right? If you need to cryptographically sign something, use Django, use the signer that Django comes with. Django auto escapes, unless you market a safe Django auto escape user data, it'll explicitly mark it as safe after auto escaping it, but the auto escape only works for HTML markup. If you find yourself needing to render JavaScript code, user JavaScript code, you use JS and code. Now, when it comes also to validating URL structure, the regular expressions provide a very, very secure implementation of ensuring that the, or at least you should be using it to provide, to provide a stopgap measure that people that shouldn't be hitting certain endpoints with certain data shouldn't be there. However, it's not perfect. Now, as an example, the default hasher is PBKDF2, password-based key derivative function two. Makes it easier to remember the long list, the set of characters when you know what it stands for, but it's set at 10,000, if you should upgrade that to 100,000, and that's as of today. Learning to all future viewers watching the video or considering this, you may need to increase that at a later point. Now, if you want, if it slows down your system, right now, 2.7.8, the latest version of Python 2.7, has back ported from Python 3, the C hash function, and you really don't have to worry about it. Another issue that we have is that object permissions aren't present within the framework, and therefore most developers don't think about them. And it's really important to remember that you have to be assertive of which user owns which object. And on top of that, the CSERF implementation in Django implicitly trusts the framework. I've got some work that I'm working on that'll implicitly trust the cookie, I'm sorry, and it bases all the CSERF mitigation on the cookie. If you have access to writing a cookie for that domain, you have effectively broken CSERF. Now, that is hard, but it's possible, and I'm working on some enhancements to the CSERF implementation to mitigate that issue. But let's talk, let's jump back a little bit to building our security controls. We mentioned that they should be in one location and we should not repeat ourselves. And all the logic should be very straightforward. This means that when you're using the login required decorator, it does not belong in your views.py, it belongs in your URLs.py. How many people have a views.py that's bigger than a thousand lines? There we go, right? How hard is it gonna be to realize that you missed one view? It's in your URLs.py that rarely grows larger than a hundred lines and works quite well. Now, I'm not gonna get into the beta function-based views versus class-based views. Personally, I use class and you'll see why I like them more later on. But whatever works for you, it's a free framework. Now, within class-based views, you actually get the ability to create mixins by overriding the dispatch method. We have an example of that here. Here we have, I hope it's easy to see, I took a screenshot from my computer. Here we have a class-based view mixin that is a login required plus it's going to require that a specific object is owned by that user. And as you see in, let's say, line five, for example, we obtain the target user based on the object. We check that in line nine. In line nine is going to make use of the request.user interface. Now, this is obviously assuming that within your application, you request.you're not saving objects as anonymous users and therefore in line nine you're checking if the user is authenticated. But then you're also checking in line nine if that user owns that object. And this is one of the reasons I like class-based views. It allows very easy mixins. And then you can use these mixins to create views, like authenticated template view, which will just have this as a mixin on the left-most side and then have the regular template view that Django offers. And you have a very simple view and you don't have to worry about putting login required. It also allows you to put all your authentication and authorization code in one easy to find place. Now, that's views. Let's talk about forms. Now, just, Django forms are fairly secure. They're built fairly well. The thing that scares me the most is model forms. How many of you have Rails experience? How many of you know what mass assignment is? Oh yeah, that's good. Just about the same amount of people that have Rails experience. That's really good. So this is something we don't have in Django or at least we shouldn't, but mass assignment is a bug where fields within your model are accidentally exposed to the internet, allowing anyone to put any information they want in those fields. Now, I've written, the Django documentation taught me to always make use of fields and I very much trust it. I don't use exclude. When you use fields, you're whitelisting. You're saying we only want these fields. We only want to deal with these, we only want to populate these fields in our model and I think this is a very good example of a properly implemented control. It makes it hard for the developer to shoot themselves in the foot and at the same time, it's also very powerful. Now, well, we've knocked off quite a few things in our list. Let's talk about being conservative. So, C-Surf is one of the things that is a popular hole that's been exploited and it's pretty scary and one of the problems that I feel that Django has, especially with function-based views, is their lack of explicit HTTP verb handling. Now, as you see here in my class-based view, I have, I'm inheriting from the Django core view and I have the ability to respond to both a get and a post but if I don't have any of those methods, it'll get a method, the viewer return method not allowed whereas a function-based view will always return based on that method. There are C-Surf holes that I've found that exist because functions were expecting a post but when you gave them a get, they pulled the variables out of request.meta and the C-Surf middleware in Django saw a get, said we don't have to check for C-Surf here and the view was compromised. So, there are, there is the ability within Django function, within function-based views to use a decorator called allowed methods but I'm not that much of a, I'm not such a fan of decorators. I find sometimes they're left out and when it comes to writing your own, it can get a little bit hairy but that's just my own personal feeling and don't take it, judge it on a case by case basis but I like to be very conservative at least when it comes to my own personal development so I shy away from writing decorators, I'm using classes and I'm being conservative and explicit about what my view is supposed to handle. Okay, now that we know what being explicit is about, let's talk about crypto. Now, I was, the original section, the original slides here were examples of how to do crypto properly and I wrote an example of cryptographic implementation on my blog in Node.js and then someone asked a bunch of questions about it and started moving things around and then I pulled my slides out of this talk and I wanna, and I wanna shut down that page or at least remove it. Crypto is really hard, right? Even cryptographers have problems with it let alone simple humans like us. It is really important to note that if you don't implement crypto properly your users can be negatively affected and therefore you have to be very conservative with what you do. Using Qizar and I'm only giving Qizar as a recommendation, use Qizar. When it comes to crypto, use Qizar. Don't implement it yourself, please and please don't play with Qizar. You're modifying Qizar, modifying the behavior of Qizar, vulnerabilities. Now I have a friend named Jan. Jan and I used to work together at Matasano and after the work at Matasano Jan and I developed an application in Django and I proposed an idea to use a cryptographic hash to identify a user and Jan let me know about Jan's rule. Jan's hash rule is simple. Only use a cryptographic hash when you need to. Now, can anyone give me examples of what a use case for a cryptographic hash that you absolutely need a cryptographic hash? Storing passwords, incorrect because these days cryptographic hashes or they used to be good for storing passwords because they're supposedly one-way functions or they're great compression mechanisms. Cryptographic hashes can be calculated very fast. Passwords you don't wanna be able to brute force. So these days we use algorithms that are tunable. Someone mentioned Bitcoin or cryptographic currency. Again, the amount of processing power that the Bitcoin network has practically invalidates anyone that uses any of the Shaw family or even, I'm not even gonna talk about MD5, but the Shaw family of hashes to hash user passwords. The amount of hashes they're able to generate that second is mind boggling. So there are two examples of Jan's hash rule in where you don't use a hash unless you absolutely need to. The one use case I know is if you want to ensure the consistency of a specific file and for example, Git uses hashes to track files. Many open source programs use hashes so people should know if the file has been modified or not. But then again, we need hashes. We need at least unique identifiers that we need to tie back to users. So for that, we have UUID4. UUID4 reads 16 bytes out of the cryptographic random source of the operating system or at least it's supposed to. If you don't have access to it, it will just use Python's random. So you have to ensure that you actually have access to it. But that's when you need a UUID. When you need a regular just set of bytes that are completely random, just read out of U random. An example of code right there. That number is completely unique. At least I hope it is. Now you need something to be signed, use Django signer. If you're stuck, you're gonna have to use the Python's HMAC implementation. But then again, once you get to the HMAC implementation, which by the way needs a hash. That's another example of a primitive that needs a cryptographic hash algorithm. You can get nailed with a timing attack, a side channel timing attack. So really just stay on the safe side, use the Django primitives. Now, I deliberately shortened this talk a little bit. Now we got almost 15 minutes. So there can be a lot of questions, but I'll end off with a little bit of an appeal. Security is a great industry. It's really good. It's made me a better engineer, and I hope if you guys do research, you can do research into security, then you will become better engineers. It's important to note the limitations. The lowest common denominator will never disappear from security. Just like the chain is only secure is its weakest link. But it's really important to do research, look things up, and when building new parts of your application, try to understand the attack surface. Don't only look at what should happen, look at what may happen. And then once you look at what may happen, you realize it's a little bit tedious because so many things may happen. So let's just be assertive and ensure as much as we can what should happen. Now, I'd like to make an appeal to the larger community. There is a lot of knowledge that we have within Django about security. There's a checklist that we should be building to help our fellow developers build and write more secure code. I know as a developer, as a security person, one of the biggest fears we all have is that innocent people, people in general will get hurt because of our code. We don't intend that to happen, and unfortunately there are parasites, attackers in the world that pray on the week and unfortunately sometimes they're able to take advantage of our code. So we should create a very basic checklist of every part of the framework of when you're writing, when you're using this part of the framework, what do you have to be worried about? And it should be really easy to use and just appeal to the community to help. And if you'd like some reading material at Madisonia, we always recommend the WA, we call it, is a web application hackers handbook too. The second edition, the first one is good, but the second edition's better. Tangled Web, the art of a software security assessment, and Microsoft also has a great book called Writing Secure Code, and Microsoft's got some good books out there. And all these books will give you the mindset, the proper mindset to building more secure code. Now, that's good, whoa. Nice, I've got time for questions. Sure, I'm gonna put these slides on my website. So, well, yes, the question part. Thank you so much, Lady. I think it looks like you've left a full 19 minutes for questions if my arithmetic serves. So please, this is obviously an exciting opportunity to engage on security matters. Looks like we already have our first question ready. Let's have a question about, you mentioned taking advantage of safety in numbers. Do you believe that there's any sort of diminishing returns there in as much as, while you may get the benefit as a developer of the collective knowledge of the community so that they can help you secure against attacks, does that not also, though, open up doors for when there is a security exploit that the payload is larger, right? If every Django project is using the same code to secure themselves, once an exploit's discovered, you have a huge swath of projects that you can exploit. So it does, and think about it in the simple forms. Heartbleed affected billions. That's exactly what I was thinking, right? And OpenSSL is a very popular library, but at the same time, it's better than the alternative. This is part of the security, you gotta kind of pick your battles. It is better than the alternative. Writing your own is not gonna get, it will not be more secure. There are very few people in the world that are able to put out solid cryptographic libraries and for them to be initially secure by default. And I don't know them. There are people that do, but no one trusts them. And things that are built by the community have got a large set of eyes on them. Yes, if there is an exploit, many people will be affected. But at the same time, every time that there is a hole in them, you know that there's so much security review that has been done that they found a slight chink in the armor. And everyone knows about it, so everyone talks about patching it right away. It's not that everyone ignores it or it's known only to few people and then you don't know to patch it and then you get hit by it six months later. Thanks. You're welcome. Should I repeat the questions or they have them good on the video? Oh, okay, please. So I have a more specific question. I'm sure other people have run into this too. So what's the best way to encrypt a field in a Django model? So say I have a user and I wanna encrypt their first and last name. There doesn't seem to be a very clear way to do this. Is there anything you would recommend besides the instinct of just hashing that value? Well, hashing it won't help you because the hash is supposed to be a one-way function. You're not supposed to be able to pull data out of it. Using KeysR to encrypt it is really helpful. You can encrypt it and then pull it back and then decrypt it every time you pull it out. I believe Django Encrypted Fields, don't hold me to it, you have to check them out, but Django Encrypted Fields uses KeysR and Django Encrypted Fields has an example that has a text-based encrypted field. Oh, okay, great, thank you. It's not an endorsement to Django Encrypted Fields. I looked at them once, they may have changed, but check them out. Is that like an add-on or something like that? Yeah, it's a third-party application. Okay, thanks. You're welcome. I also have a Django-specific question. Can you comment on development versus production settings? Example that comes to mind is allowed hosts. Sure, so most important, debug mode must be turned off. Now, you may all laugh, right? And I did when I was a Django developer and then I joined the security world and I was like, okay, now I'm gonna count the amount of sites I've seen debug mode turned off. Almost every application that I've tested had debug mode enabled in some way and it's really, really important for that. Now, also in production, you're dealing with things like rate limiting and abuse that you're not used to and it's really important to look at your, every use case is different and just set some really basic rules and guidelines to how much of your service your user should be using. A quick question that might be a little too specific, but do you have time to elaborate a little bit on the sort of spoofing the post by using a get and bypassing the C-Serve and how safe is it to trust in if you're using a function-based view whether the request is a post or not? Which is probably good, I rely on that. Sure, sure. So I'm gonna talk in the abstract and I don't have any code to show, but I'll try to be as specific as possible. So every function-based view takes a request, right? It'll take any type of HTTP request, it doesn't matter. Now within the code of that function are specific directives to process based on that request. If request.post, so if this is a post request, process the form. If request.get, do the opposite, et cetera. Now the issue I was describing was an issue that has been found where a view existed and this view used request.meta. So it wasn't just looking for a get or a post, but the developer assumed the fact that it was in a form that it would be posted to, but it can easily have been requested by a get. And that was the issue. You mentioned during talk that it's important if you do venture down the security road and writing your own software for that, your own controls, that it's important to understand all of the attacks that you may encounter and anticipate. That book. Handbook. My question more pertains to, do you think it's valuable to be able to understand and execute some of these exploits yourself in that process? That depends largely on the way a person works and learns, but from my perspective, I learned software security by looking at the framework, we're looking at the Django framework and just seeing what does it do? How does it work? And then looking at other implementations and saying, why are they different? And then comparing the differences and understanding how it can be attacked. Some people find it really helpful to actually attack. And for that, there's a program called WebGoat that allows you to a really vulnerable web application that allows you to really test out the application, to test the application security. The web application hackers handbook would give you a lot of those attacks practically. They make use of a proxy tool, a web application proxy called the Burp Suite. And for me, that's my Swiss Army knife when it comes to pen testing. And I really rely on it heavily for everything that I do. And I think that going through specific components understand and just reading about the attack surfaces on those components will be really helpful. But whatever works, if it's easier for you to break into the actual application, there you have it. And if it's easier for you to just look at secure implementations, then if it's easier for you to do both and do both. Thank you. Hello, my question is about, do you have a guideline to know when it's appropriate to step back and ask? Well, not ask, but when doing security, it's holistic. How can you know whether the Django layer is the appropriate layer to address a certain security concern with a stack with other layers? So just to expand a little bit on what you just said, why should, so for example, when building a rate limiting control, you can build it, let's say you use Nginx, you can put that directive in Nginx, you can put that directive in Django, why should you do one over the other? Now, it really depends what you're looking for. Nginx knows how to proxy and serve files very well, right? So when you want to limit the amount of IPs that hit your site, you can do that in Nginx. When you want to limit the amount of IPs that hit a specific endpoint, you can do that with an Nginx. However, it doesn't know anything about your application. As in Django, you can build rate limiters that can rate limit specific actions so that shouldn't attacker decide to abuse that specific action, you can throttle that entire action across your application. It's not bound to URL as Nginx is going to expect, it's bound to a set of behaviors. So it's largely dependent on what you, what you want to, what type of control you want to build. Both are really important. In fact, I'll say everything that you can get out of Django as in put into Nginx for rate limiting should be done before that because why start to get into the request response cycle when you, you can just stop the attack from ever happening, yeah. Django has a lot of settings around cookies, like HP only, secure signed cookies. Do you have a recommendation of how you set up your settings or do you just use the defaults or what? So it really depends on the site that you plan on hosting. For example, if your site is not hosted under SSL, then sending the secure flag in your cookies is kind of going to break the whole HTTP sessions. So generally, when I set my, talking about cookie settings, I make sure that HTTP only is set on both the session cookie as well as a C-SERF cookie and then secure, I like to host a fully over SSL. So secure on both of those as well. Now, what's important that most people don't know is that the C-SERF failure view exists by default and it's one of the easiest ways to profile if the site is actually a Django site, send a post with either a missing C-SERF token or an invalid one and you'll get back the C-SERF error view. And it'll also tell you whether the site's in debug mode or not. Now, that's, that can be problematic. Most people don't change it. It's really simple too. So my question's more about Python 3 and tools like Qizar and encrypted fields. Is there anybody working on that or any kick starters? Are you seeing any new tools coming out that support Python 3 versus what you're talking about earlier? Yeah. So I'm gonna expand your question to also PyPy, right? Qizar makes use of, I think it's a Python PyCrypto. PyCrypto is a C extension to Python. PyPy doesn't work on PyPy, doesn't work on Python 3. And the reason I chose Qizar is because Qizar is a set of executables. It's also, it's written in, you can download the executables written in Java and run them. Now, what is important is that you don't run these executables and open yourself up to command injection. But largely you can make use of those executables. Use a tool, don't use it so much as a library. And that way you're abstracted away from the internals of it. And you're just simply using, like as if you would use Cowsay in shell, you're using just a shell command. You get, you put in data, you get back data. It's that simple. Any more? Please. Lavey, it seems like a lot of, yeah, I respect that you're sort of, instead of talking about attacks, you're talking about best practices against surfaces generally. But it seems like the surface you're talking about, by and large, is the request response cycle. For example, you say, let's put all authorization in one place. But what about for async? What about if you're dispatching a broadcast and you're not exactly, you need to understand who's on the other end? I find that that logic sometimes is wanting for a home. And it seems like probably it's not URLs to outpy. So what do you do with that stuff? So this is why I chose the request response cycle. Because I don't think 45 minutes or two hours would have helped with async security. When it comes to security, it's when it comes to protecting yourself from vulnerabilities, as I mentioned previously, you largely have to assert what is gonna happen. You have to be very specific. And you have to really push yourself to understand what's gonna happen. When it comes to asynchronous programming, things are largely being handed off to different, let's say using co-routines or now event-driven asynchronous programming. You can throw yourself down a rabbit hole really fast. How many people wanna think about race conditions in asynchronous programming? Well, every bank that exists today does not make use of asynchronous programming when it comes to transferring money for the fear of race conditions. And even within race conditions, they make sure that everything is within a transaction. When you mention asynchronous programming, from my perspective, I'll look at it from the Python way of not just API calls that are being sent out to the server, because those are also handled by Django's request response cycle, whereas with Django itself, asynchronously processing certain things. One important thing to note when dealing with it, and I'm not gonna dive really deep into it, is just because it's async doesn't mean it's lightweight. And just because it's lightweight in one place doesn't mean it's lightweight in the other. For example, if you manage to find a view that you could really increase the amount of processing power that is required by that view, saying they're based on, let's say one of the most recent holes within Django is submitting within a multi-part request a set of files that will cause Django to perform an ON operation. If you can find that with an async piece of code and they're using GEvent, that person's got real problems because GEvent is great when it comes to IO and it actually isn't so good when it comes to serious CPU handling and it's gonna stop responding to everything else. So what's really important is that you rate limit as much as possible. Don't think that you can upload 300 megabyte file and it will be really easy on your system. The second thing is to remove the asynchronous parts of your code from where it can get a little bit hairy. And what I mean by that is when you have code that is gonna run, say payment system. You wanna make sure that payment system, that payment happens once and only in one location and it can't be triggered multiple times within a specific set of time. So in the regular world, you'd use locks, right? You'd lock the start of that payment, you'd move through the code and you'd end the lock. However, Python's cooperative scheduler may, especially asynchronous programming, may break those locks or may get you to the point where you may be within multiple locks at the same time and do certain things. So it's important to know when to be synchronous. That said, it does mitigate a decent amount of, denial of service vulnerabilities so your mileage may vary. I'm an educator and teach people Python programming, Python web programming and so on and so forth. And one of the most difficult areas for me as an educator is that I tend to be a fairly trusting programmer, which makes me very bad at this kind of work. Do you have any advice for educators or for students who are learning this kind of thing about ways to make themselves constructively paranoid? Well, first of all, being a trusting person is, it's great, it's, you know, unfortunately we're not as trusting as we could be, but let's just do a show of hands. How many people have invited people over to their homes? Okay, the people that didn't answer are definitely, that's a little scary. How many of you guys have known that person before you invited them over to your house? Okay, how many of you have not known that person? Excluding Airbnb? Oh, one person, okay, good. So you invite someone over to your house, you know, you see someone walking over the street and saying, hey, you look hungry, coming for a meal, right? Now you don't expect that individual to be courteous and to know their boundaries, right? Not to put the silverware in their pocket, not to harass the other members at the table, et cetera, and largely they're very nice individuals, they will be like that, but when that person oversteps their boundaries, at that point you kindly show them the door, right? Now, when it comes to building software, we don't always have that luxury of being able to handle just one request and ensure that everything is working nicely around it. So we try to assert as much as possible, place all the rules around that one request, that guest in our house, and say these are the roped off areas. You can only go into the bedroom if you're a member of the family, you know? Okay, everyone can wash dishes, but you can only do certain things, you can only turn on the TV if you're trusted, you know, you're a staff member, you're a member of the family, you can only change the channel if you're old enough, if you're older than, let's say 18, right? Or 16. Now, that is kind of how you have to look at your users within your application. You're going to have, the majority of your users are going to be good, hardworking people, hardworking, sorry about that. They're going to be good, well-minded individuals, but you're going to have that 1% that's going to literally just probe you to find your weaknesses. And being assertive from the onset is really important. Now, the assertive part of security actually comes to me from a different part of my life as you may have realized, I'm a religious Jew, and you use them as a set of laws. Those laws are largely written in many places but are collected in a book called the Talmud. Now, I don't think many of you have learned the Talmud here, but the way every law in the Talmud works is that you take, they discuss the law. They say, we know this is supposed to happen or we know this is the law. Now, let's look at the limitations of it and they hypothesize everything. And from a very rough piece of stone, which will be the original law, they sculpt a masterpiece of every single facet when it should be done and why it should be this way. And this is, I've taken that part of my life and built it into writing software and writing secure software in a way where all the code that I put out I'm very explicit. What should happen and why should it happen? And I don't look at kind of the, okay, I hope it's all gonna work. I kind of, it's not that I'm not trusting of my users, but I'm just assertive and I say, you are only a user if you meet these requirements. The same way, if someone walks into your house, they're only an invited guest if they can accept common courtesy. No more questions? Nice. All right, Lady Gross, thank you so much.