 My name is Justin, I'm president of the online internet everywhere, it's talking to me. I'm going to be talking about rail security as indicated by the title of the talk. Quick announcement though, there's another security talk schedule, the same time slot. Everything is changed about that talk except the room. So the title changed, the reasons are changed, and the time changed. But it's in that same 204 each. So if you're like, oh man, I wish I were going to that other security talk, you can still go to that talk and go through this one too. So I just want to make sure you know about that. In case you're wondering what my credentials are to stand up here and talk about security, and if you came to this talk wanting to know how to hack, I got it right here for you, I figured it out late last year. Turn off the lights in your room, turn on the backlight on your keyboard, and start hacking. That's all there is to it. If you came to this talk to learn how to hack, you're done. Okay, I hate agenda slides, but I thought I would do one anyway. Because I want to make sure that you know what this talk is going to be about. This is not going to be a talk about the OAS top 10. It's not going to be an in-depth talk of how to hack Rails or anything of that nature. This is really kind of a very broad overview of what Rails gives you security-wise. What it doesn't give you, that's actually the bigger section, and it's really more like the complaining about what it doesn't give you. And then a very short section at the end about what to do about this situation. So first up, cross-site scripting, always have to start with cross-site scripting. Rails 2, who's using Rails 2? Yeah, see, never goes away. So back in Rails 2, kind of a bad situation. You had to make sure you manually escaped everything in your views. Rails 3, everyone rejoiced escaping was the default. Yes, I'm sure some people were upset that they had to go through and like remove all those h's from all their views, but this is like way better from security standpoint. Everything gets escaped by default. In case you're unaware, this is what it looks like to write views in Rails. If you don't do anything, it's escaped, views raw, it's not escaped. If you use .html save, it is not escaped. What happens when you don't escape things? You get cross-site scripting. My favorite one looks like this. This is a super neat attack, calling alert 1. That's my favorite one. A little bit more complicated. You may have seen this. Quite embarrassing. A little last year, a tweet deck had an excess problem. So it managed to fit this script into a tweet. Effectively called part tweet. And essentially what it did was it would click its own retweet button. So if you saw this tweet in a tweet deck, it would retweet itself. As you can see down there, about 84,000 retweets with this screenshot mistaken. Well, I don't know when this screenshot was taken. It was during the whole incident. And that part is not actually extraneous. It's the key to the whole thing. I can tell you about it later if you'd like. If you want to scare yourself and your friends, you can use WEEF, which stands for Router Exploitation Framework. It's not related to me in any way, but it's actually a rail, not a Rails app. It's Ruby and WEEF is built on Sinatra. And you can do horrible things if you find cross-site scripting on site. Check it out if you're interested. Rails gives you a lot of pretty safe helper methods, which you should use. It's kind of nice. You don't have to write a lot of HTML by hand. And HTML, no, that's not true, actually, you do. But you can use these tags. They're safe-ish. I can't vouch for their total safety. Certainly things like content tag or other sort of generic tags where you just drop in your own HTML. Probably not very safe. You should be careful. All right. Excesses. I love this example because this is an example everyone uses for cross-site request ordering. You have your website or your bank website open to one tab. You go to some evil website. It makes your request to your bank. And you have this transfer of some money. Now, I want you to notice, though, that my bank account has so much money in it. I wouldn't even notice if 100,000 disappeared. So, you know. But other people, you know, they probably care about that and not money. Does anyone find, like, this pack kind of strange? Like, why did one website make your request to another one? And, like, it affects your login session? Is that weird to anyone? It's kind of weird to me. Does anyone know the answer to why that happens? And why does this even work? Yes, who said that? I like you a lot. The one weird answer is cookies. Yeah. So your cookies get sent along. So if you're logged in, the request will be as if you're logged in. You're probably all aware of this, but I just want to make sure that we're on the same page here. So Rails, out of the box, it's offered this way all the time. It's really nice. Gives you C-SERF protection. I'm going to say C-SERF because it's way shorter than cross-site request 4.3. The fancy term for this is synchronize your token pattern. You have a token in your session. You have a token in the form. When the form gets submitted, you validate that the token in the form is the same as the one in your session. It probably came from that user. You're all good to go. You probably all know this. Add some meta tags to your page so you can pull it out in JavaScript if you need to. Use the form helpers. It gives you this hidden input with an authenticity token. And it all just works. It's all great. Other frameworks would, I mean some other frameworks would love to have this kind of thing. Other frameworks have other frameworks. Mess assignment. It's awesome because everyone knows about it because of GitHub. And it's sad for GitHub. But it's good for the Rails community as a whole because people find out, hey, this is actually a problem, not just a cool feature. So this was the old way. So just drop your rounds in and save. And if you do that, someone can drop in like admin equals true. And it sets it up model. And now there you go. So now we've got to revisit some history. Okay, so Rails 2. You could wait for blacklist, the attributes that you can mess assign on models. Then in Rails 3.1, it became an option that you could pick to say all my models must have a waiters. Those are nice and true then. Rails 3.2.3. If you generate a new app, then that configuration was set to true by default. Also very nice. Rails 4, strong params came along. Now you have to waitlist on assignment. This is also pretty good. There's different philosophies. And if you still want to use the old way, waitlisting it on the model, there are gems that will allow you to do that. But all in all, this is good stuff. It's moving in the right direction, right? Towards the scene. That's the way we want to go. Looks like this. You probably don't know. If you require a parameter area, but anything else in that comes in, it's not going to work. Rails, by default, will use a cookie session store, which means all your session stuff goes into a cookie. Rails 2.3, that was assigned session cookie. It's nice. So use the secret value, sign it, and basically, yeah, you have this cookie sitting on your machine, you couldn't really change, right? Because that would be really bad if you could just arbitrarily set values in your session. That would be quite bad. Rails 4, they switch to encrypted session cookies, which is also like a good move, and they switch to using JSON, not marshaling and un-marshaling. It's also a good move. So again, we're moving in the right direction. These are all good things. I'm telling you all the good news up front. Right? Simple injection protection. Actually, just like saying, injection protection. Injection protection. All right. So Rails 2.3, you have your nice parameterized queries. That's the way to do it. Everyone knows parameterized your queries. Rails 4, introduced R-Roll, or R-Roll, or A-Roll. As far as I can tell, if you use that, it's safe. I could be wrong if you're here and you know that I'm wrong. Please let me know. So I stopped saying that. But it seems like it's pretty safe. I give you built-in queries to using that. It's basically safe from injection attacks. So, cool. Rails will give you all these nice, nifty security headers. So, X-Content type options set to no snip so that Internet Explorer doesn't try to guess what content type you're sending, which always ends badly. X-Train options set to same origin, so no one is hiring you, and for click-jacking attacks, XSS protection turned on, set to blocked, tell the browser, hey, if you happen to implement automatic XSS protection, use it. I'll give things. If you set force SSL to true, then you'll get a list of yes headers, which basically tell the browser, hey, never use a clean HTTP connection to connect to me. Always use SSL. Even if you click a link that isn't SSL, use SSL anyway. So that's nice. Oh, we got through that fast. Okay. So like I said, this is kind of, this is mostly me complaining, and hopefully you take some of this. I'm hoping that people here will take some of this and say, I'm going to commit fixes for this to Rails, and everyone will be happy. Back to cross-site scripting. I'll give you a moment to read this slide. Okay. If you think no one gets this wrong, you are wrong, I have talked to people, and they said, oh, it doesn't make it safe. So, I mean, you got to think about something coming in Rails, they've never used it before. They see this method. Looks like it makes it safe. It doesn't make it safe. Unsafe. This I just found out this week. I don't understand it. If you understand it, please let me know because I'd like to be wrong, but it looks like even in the latest Rails 3.2, it does not escape JSON when you call it to JSON. I don't understand, but if you do, please let me know. Rails 4, it's awesome. It encodes it with the like backslash U. It's totally safe. On the client side, it doesn't matter, it's interpreted the same, but it's safe from cross-sites scripting. You know what would be really nice, though? Is if we had contextual encoding. Because who knows what all these methods do? There's one called sanitize. Sanitize what? From what? To what? I don't know. I mean, I do know, but you can't tell from the name, right? And then you have like HTML escape, escape once, escape JavaScript, escape once, escape. Like cgi.escape. I don't know. I mean, I do know. Could you guess what it does? Probably not. You know what's nice though? Contextual encoding, which tells, it can tell where you are on a page, if you're inside a tag, if you're in JavaScript, if you're inside an attribute, and then it does the proper escaping. It's really cool. It would be nice if someone would implement it. Cicer protection is pretty awesome in Rails, but it's not as awesome as it could be, right? So you have to make sure that actually, you're using posts, or something like posts. So if you're using git, you know, you don't need protection. And you have to make sure that you don't even allow git, right? It's just because your web app is using posts, doesn't mean the endpoint will accept the git. If someone sends a git request, you don't get Cicer protection. Another thing that's kind of, you know, just a fact of light, is you've got to use the form helper if you want those automatic tokens inserted, otherwise you've got to do it yourself. Another thing to be aware of, Cicer tokens persist per session, so they kind of hang around for a while. It's not necessarily a bad thing, but you can kind of imagine that you might want that to be less long-lived than a session made. What happens when there's a failure when you get a token and it doesn't match what you expected? These, if these look like odd version numbers to you, they did to meet you. So Rails 2 through 3.0.3, it would raise an exception. You know, a price seen in it. Rails 3.0.4 through 3.2.1, which is the latest, 3.2, it calls a method called unverified request, and then it just resets the session. But the request still gets processed. It's just the session gets reset. Rails 4, the default, if you generate a new app, is to raise an exception. If you don't give protection for ordinary options, though, it goes back to this, oh, we'll just clear out the session. So what? Why am I talking about this? Imagine you had an awesome method like this, where all I'm doing is taking the parameters and transferring monies. I believe the transferring monies looks like this or something. I don't know. I'm not a big... So, the two links down at the bottom, the first one was from GitHub's bug bounty. They just published it this week. They paid out the bounty because of a bug where they were actually caching the session. So Rails would clear out the session, you know, like when you actually use the variable session. That was cleared out, but they'd cached those values somewhere else. So it did no good. The second one is a block from Invisium from last year in some client's code. The client had implemented the sessions in a totally different cookie. So it wasn't in the Rails session cookie, it was in some other cookie. So yeah, I cleared out the Rails session cookie, but not the one that they were actually using. So that's bad. I mean, ideally when you have this kind of failure, just stop the request. Why would you ever want to continue processing your request when it seems like someone's performing an attack? So, raise exceptions. Yeah. Speaking of sessions, this one still blows my mind. Server-side sessions are not the default. You may be saying, yeah, cookies are so fast but it's awesome, I don't have to have the database. But did you know that when you install Rails you have to install a database? So we're using the least safe default which is using sessions, sorry, cookies for sessions. When we could just be using a database because you have to install one anyways just to run Rails new. So what? Well, Rails session cookies are forever. If you get a session cookie, and we're talking about using the cookie store here, it lasts forever. It's valid forever unless you code something on the server side to deal with that. Otherwise, they're valid forever. The probably even bigger problem though is that you can't manage it on the server. You want to tell your user, hey, you have like five sessions and one is in China and you're in Atlanta. That's something you'd like to tell your users as a security feature but you can't because you don't know what cookies are out there until they actually get sent to you and you have no idea. By default, this is the default thing. Pre-Rail score when cookies are correct and encrypted they're super simple to decode. So if you came to this talk and you're like, I want to be a hacker. If the keyboard and the dark thing wasn't good enough for you, here's the second step. This is how easy it is to decode a session cookie from Rails. You just split it because the second thing after the dash dash is the signature. We don't care about that. Basically 64 decode it. Load it with Marshall. Boom, there's your session. That's the major problem with storing sessions in cookies is that you may accidentally put something sensitive in it. I don't believe that. Probably you're not actually putting this stuff in it, but you never know what someone's going to put in the session. So, that kind of sucks. This one. Who here has a Rails app and it doesn't have a user model? It does not have a user model. I'm seeing like less than 10 hands. Okay. Rails doesn't have any like account management stuff built in except for it has secure password, which I, you know, okay. It's good to have. So, it's kind of crazy that that's not built in to me. It'd be nice if it was. No authorization framework. I guess you can, you know, build stuff with your before filters. This is an even bigger problem though. The Rails doesn't provide you any protection against directory traversal. So, it will happily render any file that you give it, no matter where it lives. And you can sit in any file, you know, if you have a code that looks like this. And remember that it's, when you render a file, it's actually executed pretty good. So, keep that in mind. This, though, depends a little on your server setup. Your web server itself may actually have this kind of protection. Hopefully you're limiting what your Rails app can actually access, or things, but out of the box it doesn't give you anything. Am I complaining enough? Alright. And again, this isn't because, like, I'm trying to disrail for anything. People say distil, disrails. Just make me feel really old. Okay. But because I'm hoping someone will fix it. And I'm hoping that someone's not me. Anyway, I double checked. Last night, all these methods are vulnerable to SQL injection on the latest Rails. You may be surprised because they look very innocuous. I made a website, Rails sqli.org. It lists a whole bunch of methods, active record methods with some example queries. And you can go look at it and see what to do. But what a lot of people don't realize is that you could clone that, like a Rails app. A very horrible Rails app where you can plug in whatever queries you want and play around with this. And it gives you sort of like, okay, this is the code that's going to execute. You can put in the parameter value for, you know, for this parameter and then you can run it and see what happens and check out the query and see the results and just kind of play around with it. I believe it updated for Rails 4. I went through, I think, with 4.0 and updated some things. What I would really love is someone else would go through and update it with, like, Rails 4.2 information because there may be new methods or there may be old ones that are gone or there may be old ones that have now come safe. It's possible. So just go there, download it, send me a pull request that would be possible. This is the most bagging I've ever done in a talk. But sometimes queries are so complex that you can't use the SQL methods that are provided by Rails. That's a joke about this query. Sorry. But, you know, sometimes you end up building these giant strings and, you know, you're like, well, how do I sanitize this input? So you might go look at the docs and be like, well, sanitization, that sounds good. And you know what else sounds really good? Sanitized SQL. That sounds exactly what I want. So you put it in your code because you don't actually read the docs. That's important. You just put it in your code. You put it in your code and you run it and what happens? Nothing? More than nothing. I added a method. What happens? You get this. A defined method. But let's say you did a little bit of digging. You're like, ah, it's on the class. So I'll just get the class and call sanitized SQL. What happens? Does anyone know? Private method. It's a protected method. We're Ruby is here. We don't believe in protected methods. So you're right. It's a protected method. That sucks. They don't give you an API. Just make your own. All right. So let's try this out. We're going to have classic SQL injection input here. We're going to pass it in to sanitize. That's on what happens? This is the most interactive part of the talk. No one knows. Because who knows what happens? Correct. Correct. Why? Because you didn't read the docs. It's actually expecting something like this. It works. It's not fun, so I'm not going to ask you. This is what escaping single quotes looks like in SQLite just kind of doubles them up. So, okay, we got that working. There's also this form which gives you a slightly different query. That's cool. Way harder than I think it probably needed to be. And probably some of you in here are like, yeah, but that's because you were in an instance method. If you were in a class method of your model, that would have worked just fine. You're incorrect, but I mean, come on. I just looked up the method and tried to use it. And it was really hard. That should be better. You got to do it yourself. Perfection, really awkward. You could like use URI parse and get the path, but actually you have to do something more like this because it will raise an exception if it's not a valid URI. So I wish there was just a safe redirect. That would be nice. Who in here is a Rails core committer? Does this look familiar slash dangerous to anyone? That home URL probably came from user input and therefore it's not safe and it's not escape. Yeah, it's not safe, but I'm sending it to link2, isn't that safe? Yeah, yeah, exactly. So I'm going to just put this in and assume as soon as someone clicks the link, there you go, success. My favorite one, which is a lurk one, post and a couple of talks. Apparently a couple of years ago I didn't realize it was so old. Rails insecure default. So there's a whole other list of things that Rails doesn't give you. Some of which have changed and some of which haven't. So you can check that out. You're all waiting, where's the cat picture? When's he going to shell this as cat? I know you were. Yeah, you can follow my cat on the internet and have him photo the cat. He's very lonely, he wants more followers so he asked me to throw him in here. Okay, to wrap this up I'm going to go through this kind of quickly because people probably have questions or corrections that they would like to shell at me. So what to do about it? First step. Learn about security. You've all taken the first step. Congratulations. Good job. Next step. Fix all the things that I just mentioned. That would be nice. That would be nice if someone did that. That would be really nice. You can use some libraries. This is not like a comprehensive list or even necessarily recommended libraries. But these are some libraries that exist that you might want to check out. Rack attack for rate limiting, secure headers or secure headers. But in particular, you want to add content security policy to your site, which you do. You can ask me later about it if you want. Access control. You're probably familiar with the libraries we've had. Everyone uses on the off and the bias, so you're familiar. That's a good idea. You might want to use some static analysis tools. There's one called Breakman. I don't know, it's kind of good. You might want to try it. Some guy wrote dependencies for known vulnerabilities. And it also would be kind of cool if more people sort of jumped on that and contributed to the I didn't look it up, so I forget the name of it, but the gate repo that it actually pulls the vulnerabilities from. I think that actually needs more people pushing the stuff to it. Nice thing about static analysis tools. I don't know if you've ever seen a graph like this. At least 50 of them on the internet. They all kind of look like this. The idea is on the left, you probably can't read it because they're also small. On the left, that's like when you start developing. You're doing your planning, your design, that kind of stuff. On the far right is you've already deployed. And the graph is the cost of fixing problems at any point along that graph. Problems could include security problems or other bugs. But we're in a security talk, so security problems. If you fix it way on the left, it's cheap. If you are typing code and then you back slap, back slap, back space, back space, and then type new code, that cost almost nothing. What about like you're in a design meeting and someone's like maybe you don't do it that way, you do it the same way. What did that cost? Almost nothing. That's awesome. That's what you want to do. At the other and you're at home, asleep on the weekend at 1am you get paged and you have to get out. You fix the security vulnerability. The cost is through the root. Not to mention if the users are affected and business is affected all of that stuff. So cost is very high. The point is you want to fix stuff early as possible. Nice thing about static analysis. I'm going to get unbiased, but the nice thing about static analysis is you can do it really early. This is a plan that came up with Twitter, which is where I work, which I didn't even mention, but sorry, forgot. This is the plan that we came up with. It's not a bad plan. The plan was use static analysis so that we can do stuff early. Look at all the code, before it ships. That's a good thing. My personal favorite don't fix vulnerabilities. Prevent them from ever. Get them out of the code. Don't ever ship them to production. That's the ideal. Options for doing that, you could use something like guard or guard breakman and run as soon as you change code and save file. It's pretty cool. You can get into your commit tools somehow. It's a good place. Continuous integration, maybe with the Jenkins plugin for breakman. It's not maintained though, so just be aware that people tell me it still works. Whatever continuous integration you use, it's really easy to throw breakman in there. Lots of people are doing it. If you can get into your release process somewhere, maybe right before code ships you run breakman on it or run their audit or some other tool, that's also good. Just some options for you. If you're interested in more about that kind of thing, this is extremely self-promoting, but you can watch these two talks that I either gave or was involved in. The first one was at Netflix, and it's really short. It's a good, like, inst version of lessons learned with trying to get security into the software development lifecycle and stuff. And the one on the bottom is the one that people got really excited about a few years at conference. Myself and my co-workers talked about automation stuff. People really like it, and you might like it too. Be safe. I'm at president B, at breakman, and don't spread it around or anything, but we're working on a commercial version of breakman. If you're interested, don't talk to me. That's it.