 Hello. Oh, this thing's on. Hi, everyone. I'm Stefan Bovach, and I work for WordPress.com in the VIP team. And I'm going to be talking about security today, and specifically WordPress security, but a lot of the general guidelines apply to writing code in general. So here's what I'm going to talk about. I'm going to start by saying why you should always write secure code. And then I'm going to tell you how to escape output, sanitize input, check user permissions, and verify user intent. So why should you always write secure code? Something I hear once in a while is, oh, no, my site only gets a few people. It's not going to get hit by traffic. It's not an important site. It's not like Time Magazine. It's just like my mom's cat blog. And that is actually a mistaken belief, because most of the time, your site is not the target. That's true. But they just target everything. So you're going to be hit no matter what. It doesn't matter if your site's important or not important or anything. Another common thing I hear is that security is slow. And we've made a bunch of benchmarks, and you can Google for that. But security is like adding escaping and adding WP cases, which I'm going to talk about on your site, barely equal to one mediocre SQL query. So you should always add security. You should add as much as you can, and not worry about the performance of your site. And I'm going to think about some other reasons later and put them on there. So let's talk about escaping. So why should you escape variables? And you'll notice as I go through the examples that some of them will still be insecure after a thing, but we're going to go and through the whole talk, we're going to completely secure them. So what happens? So let's say you're using the get variable and you say username, which is something lots of people say, they're like, okay, enter your username, and then you output it back on the screen. So if you do this and output the username, what if a user puts in username equal script alert bad? So what's going to happen is you're going to see that script being run and interpreted by the browser. So you're saying, okay, but script alert bad, that's not actually like a bad thing. I don't care if I see like a pop-up if they made that happen. I mean, how is that going to break anything? So it's not, the alert is not going to break anything, but you can easily steal cookies. So here let's say I say username equal and then create a script and then encode the cookies and send them to my personal server. So what happens is that you can get values that are thought to be secure and have them sent to an external site. So one thing people say is like, oh, no one's going to click on a link that says script tag and alert bad and cookies and et cetera. But what you can do is you can encode all of the values and it's going to be interpreted by the browser. So if you look at the top, that just looks dangerous. You're just like, oh no, no one's going to click on that URL. But if you look at the second URL, which is the exact same thing, people are just going to be like, oh, it's just a bunch of web gooply boop and it's bound to be safe. I mean, what could possibly go wrong? So the first thing people think about, they're like, all right, got it Steph, I understand. How about I use strip tags to remove all the tags from the things I'm going to echo, right? That's bound to fix everything. So let's say you were to use strip tag and you're like, okay, I want to let people have hyperlinks and B tags and I and images. Usually you don't let that in a username but for this example, let's say it was comment. But what if people do this and they pass image on error alert equals bad? So that's going to actually run that code because there's going to be an error. And although we thought that images were safe, what we can also do is put let's say a B tag and say on click alert bad. So let's say they click on the name because it looks like a URL. They're going to run the arbitrary JavaScript. So one thing that's been really popular recently, I guess, is using the image on error. So let's say someone does a comment on your website and you let them put images. You're like, oh, I'm going to strip tag all the nasty stuff but I'm going to leave images on so they can put that. Well, someone can just put this in the image and that's going to run automatically because source throws an error. So it's going to send all your information to a remote server. So let's talk about a bit more on escaping and sanitizing and database values. So let's say you're like everything in the database is safe so I don't need to escape it, right? But often people will be like, okay, I'm going to insert something in the product review here and the value I'm going to strip the tags because I'm safe like that and I'm only going to keep the A, B, I image, et cetera. But now when you pull out from the database, your JavaScript here and the bad stuff is stored in the database so you're going to echo it. So that's how you can get consistent. It's not just like, oh, someone put in on a URL parameter and it's not going to happen to every other user. It's just for themselves so it doesn't really change anything. But they can store bad data in your database and then you'll be stuck with it and all your users are going to see it. So what you can also do if you're clever and this depends on how you're escaping, but you can just be like, okay, I'm going to remove all of the tags, all of the tags and then I'm going to be safe. But what if someone puts two comments and the first one, they have this image source and then in the second one, they have that and those look like great comments. You want to have those great comments. You want people to love your product but then what's going to be happened is the two comments together are going to end up being interpreted by the browser. So even if you try to strip all the tags, since those aren't valid tags, depending on how you did it, it's not going to work. So that's why you should always escape yourself before you wreck yourself. And there's built in the escaping functions in WordPress which help you do a lot of things. And one of the things that is very useful as long as you're aware of it in the WordPress escaping functions is that they'll never double encode. So you can always just be like, I'm not sure if this is encoded or not. I'm just going to run it again through that. So it's just something you need to be aware of but how you can just often just be like, I'll just escape it anyways. So there's a few functions. There's escape HTML, escape attribute, WP cases which is a series of functions and WP strip all tags. And there's escape URL, escape JSON and escape JS, sorry, and WP JSON encode. And I'm going to talk about these a bit more in detail here. So when should you use escape HTML and when should you use escape attribute? So if we look here at the top and we were like, okay, instead of echoing the random string that I got from the user, I'm going to echo it inside the escape attribute or I'm going to echo it inside the escape HTML. So before that was going to be interpreted here, right? That image thing. Whereas after it's going to be safe. It's going to be encoded. So it's not going to be run as code by the browser but it's going to literally show these characters. So this is going to show up on the site but it's not going to be encoded. It's not going to be a live JavaScript that can be run by the browser. So WP cases is a function that strips evil scripts. And what it does is let's say when in my previous example where I was like, I'm going to strip tags but I'm going to keep the image one. That's the one that helps make it secure so that you know you can trust this image tag. So for example, let's say this is your string here and there's the on error alert bad that we had before. If you run it through WP cases post, what happens is it removes everything that shouldn't be there. So before we'd have the on alert bad and now the whole on error is gone. And we only left with the source and the valid href here and the hrefs on click that was bad is also removed. So you can always pass things through WP cases and it's going to strip all the evil scripts and also remove the evil attributes. There's a few functions for WP cases. The most easy one and the one that applies 99% of the time is WP cases post. So it has a bunch of pre-built defaults and by default it's going to strip out anything that you probably weren't expecting. But now if you have like a web app or something it's also gonna remove attributes that it doesn't think are valid. So anything like data dash or et cetera. So what you can do is you can run either WP cases and then pass it a list of allowed tags and allowed attributes. So you can fully customize that. So let's say you only want a tags then you can do that there or you want to allow style on a certain tag. You can also use the WP cases allowed HTML filter to change the default list of white listed arguments. So if you have your data dash ID attribute you can put it in the allowed filters list and then it's not gonna get stripped when content is run through WP cases. Escape URL is also a fun function and it not just escapes your URL but it tries to fix them up if there's something wrong with it and it's gonna get rid of anything that shouldn't be in the URL. So you see here the script tag, the lesser than and greater than sign are just removed completely because they shouldn't be there. And so other things is let's say you escape a URL called stepblavad.ca it's going to add the HTTP at the beginning or HTTPS if you're running a HTTPS site. Escape.js is the one that's most often misused. Escape.js should only be used inside of attribute tags. So when you're doing this, let's say, what you can do is do on click and then alert. So on click is a HTML attribute and then you do alert and escape.js username. What you shouldn't do is let's say you have a custom script block that you're outputting for some reason. You shouldn't use escape.js in that context. So what differentiates escape.js from escape.html and escape attribute is that the single quote is allowed in escape.js. It also is gonna remove line endings. So slash r slash n so that your JavaScript doesn't break if you put it inside an attribute tag and you have a line return that you weren't expecting. So what you should do when you're outputting arbitrary JavaScript values is use wp-json-encode. So wp-json-encode is a wrapper around json-encode which supports all the new parameters of json-encode in the previous version. So let's say you're running 5.2, which you shouldn't be for no reason whatsoever, but let's say you are. The extra parameters that json-encode has from, I think 5.4 and upwards will be supported by wp-json-encode so you know that your script is not gonna fatal on some old servers. So one thing to keep in mind when you use wp-json-encode is that you shouldn't use quotes outside of it. So before here we had like a quote around the escape.js whereas with wp-json-encode the values, let's say it's a string is going to be encoded and wrapped in quotes. So next thing is to sanitize data. So how are we gonna do about that? So this is the classic comic that everyone saw from XKCD about how if you don't sanitize your data, your database is gonna drop because someone's name is Robert Drop Table Students, which is a great name. I'm gonna probably name my kid that. So what happens is that you can run a drop inside if you haven't sanitized your data. So let's say here, okay, we're using strip tag again, we're removing all the bad stuff, but if someone puts in and review equals apostrophe, semicolon, drop database, that is probably going to be run. And that's kind of a bummer when you lose your database. So how do we sanitize database? So the first thing you should always do is use a prepare statement. So here we see that you're using insert into product review values, and then %s, and then the value get review is sanitized for database entry. Now that's safe and that's good. It's not as optimal as it could be because you should always also strip as much stuff as you don't want and are not expecting as soon as you get it. So you should get and pass it through WP cases post. So it removes other nasty stuff. So if ever down the line, there's something that's insecure, it's still gonna be relatively okay. So, escape like is often also misunderstood and misused. People think that, oh, I just write my query and I'm gonna escape like it, so it's gonna be safe. And then they're just gonna build their query like this and you see there's no use of prepare. It's just passing escape like and then we sanitize the text field, which is a function I'm gonna talk about later, which is supposed to sanitize stuff, so we think it's safe. But then if the get review has bad things, it's still gonna go through because escape is safe.