[Script Info] Title: [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:17.30,0:00:19.96,Default,,0000,0000,0000,,AARON SUGGS: All right. Can people hear OK? Dialogue: 0,0:00:19.97,0:00:21.37,Default,,0000,0000,0000,,I'll go ahead and get started. Dialogue: 0,0:00:21.37,0:00:24.05,Default,,0000,0000,0000,,So this talk is Rack::Attack and Dialogue: 0,0:00:24.05,0:00:27.38,Default,,0000,0000,0000,,how to protect your app with this one weird\Ngem. Dialogue: 0,0:00:27.38,0:00:30.93,Default,,0000,0000,0000,,Where does Rack::Attack come from? We built\Nit at Dialogue: 0,0:00:30.93,0:00:34.40,Default,,0000,0000,0000,,KickStarter. If you haven't heard of KickStarter,\Nit is Dialogue: 0,0:00:34.40,0:00:37.61,Default,,0000,0000,0000,,a funding platform for creative projects.\NSo somebody has Dialogue: 0,0:00:37.61,0:00:40.69,Default,,0000,0000,0000,,an idea for a film, a comic book, an Dialogue: 0,0:00:40.69,0:00:43.83,Default,,0000,0000,0000,,open source project, a gadget. They, they\Nput their Dialogue: 0,0:00:43.83,0:00:46.72,Default,,0000,0000,0000,,project up on our site. They can offer rewards Dialogue: 0,0:00:46.72,0:00:50.43,Default,,0000,0000,0000,,for various pledge levels. Their friends,\Nfamily, strangers on Dialogue: 0,0:00:50.43,0:00:53.37,Default,,0000,0000,0000,,the internet come and can, can give them money. Dialogue: 0,0:00:53.37,0:00:56.05,Default,,0000,0000,0000,,At the end of the deadline, if they've reached Dialogue: 0,0:00:56.05,0:00:57.55,Default,,0000,0000,0000,,their funding goal and so they have enough\Nto Dialogue: 0,0:00:57.55,0:01:00.75,Default,,0000,0000,0000,,reach their project, that's when we process\Nthe transactions Dialogue: 0,0:01:00.75,0:01:02.80,Default,,0000,0000,0000,,and the creators' get the funds they need\Nto, Dialogue: 0,0:01:02.80,0:01:03.98,Default,,0000,0000,0000,,to do the project. Dialogue: 0,0:01:03.98,0:01:06.94,Default,,0000,0000,0000,,To give you a sense of scale for what Dialogue: 0,0:01:06.94,0:01:09.00,Default,,0000,0000,0000,,we do, we, we recently crossed over a billion Dialogue: 0,0:01:09.00,0:01:11.53,Default,,0000,0000,0000,,dollars pledged to the site. It's over a million Dialogue: 0,0:01:11.53,0:01:14.96,Default,,0000,0000,0000,,dollars a day. And it's gone to over 60,000 Dialogue: 0,0:01:14.96,0:01:17.08,Default,,0000,0000,0000,,creative projects. Dialogue: 0,0:01:17.08,0:01:21.76,Default,,0000,0000,0000,,Quick introduction. My name's Aaron Suggs.\NI go by Dialogue: 0,0:01:21.76,0:01:24.91,Default,,0000,0000,0000,,ktheory on social media. I love dancing in\Nmy Dialogue: 0,0:01:24.91,0:01:29.96,Default,,0000,0000,0000,,bear outfit. And I'm the operations engineer\Nat KickStarter. Dialogue: 0,0:01:29.96,0:01:33.41,Default,,0000,0000,0000,,We, we have a very dev ops-y style workflow. Dialogue: 0,0:01:33.41,0:01:35.45,Default,,0000,0000,0000,,So, so it means I end up writing a Dialogue: 0,0:01:35.45,0:01:36.88,Default,,0000,0000,0000,,lot of Ruby code, and I love writing Ruby Dialogue: 0,0:01:36.88,0:01:37.88,Default,,0000,0000,0000,,code. Dialogue: 0,0:01:37.88,0:01:41.98,Default,,0000,0000,0000,,So, so Rack::Attack is, is a tool I wrote, Dialogue: 0,0:01:41.98,0:01:46.26,Default,,0000,0000,0000,,and it's Rack middleware for blocking and\Nthrottling abusive Dialogue: 0,0:01:46.26,0:01:49.33,Default,,0000,0000,0000,,requests. What do we mean by abusive requests?\NThese Dialogue: 0,0:01:49.33,0:01:52.16,Default,,0000,0000,0000,,can be things like malicious attackers trying\Nto take Dialogue: 0,0:01:52.16,0:01:55.37,Default,,0000,0000,0000,,down your site, doing things like trying to\Ncrack Dialogue: 0,0:01:55.37,0:01:58.51,Default,,0000,0000,0000,,user accounts or get sensitive information,\Nor it can Dialogue: 0,0:01:58.51,0:02:02.05,Default,,0000,0000,0000,,be naively written scrapers, who are just,\Nlike, people Dialogue: 0,0:02:02.05,0:02:04.60,Default,,0000,0000,0000,,on the internet doing weird things as they\Nare Dialogue: 0,0:02:04.60,0:02:07.91,Default,,0000,0000,0000,,prone to do, and that's cool, but sometimes\Nit, Dialogue: 0,0:02:07.91,0:02:09.79,Default,,0000,0000,0000,,it is a lot of traffic. It's a lot Dialogue: 0,0:02:09.79,0:02:12.30,Default,,0000,0000,0000,,of resources for your app to try to handle, Dialogue: 0,0:02:12.30,0:02:16.31,Default,,0000,0000,0000,,and Rack::Attack is a very elegant DSL and,\Nand Dialogue: 0,0:02:16.31,0:02:18.56,Default,,0000,0000,0000,,way for dealing with these sorts of things.\NSort Dialogue: 0,0:02:18.56,0:02:22.19,Default,,0000,0000,0000,,of constraining their behavior so your website\Nstays up. Dialogue: 0,0:02:22.19,0:02:27.02,Default,,0000,0000,0000,,Rack::Attack is on GitHub at slash kickstarter\Nslash rack-attack. Dialogue: 0,0:02:27.02,0:02:30.16,Default,,0000,0000,0000,,It's an open source Ruby gem. There's a README, Dialogue: 0,0:02:30.16,0:02:34.05,Default,,0000,0000,0000,,sort of exactly like what you'd expect. Dialogue: 0,0:02:34.05,0:02:36.86,Default,,0000,0000,0000,,So the big wins that KickStarter has gotten\Nfrom Dialogue: 0,0:02:36.86,0:02:40.25,Default,,0000,0000,0000,,using Rack::Attack, and the reason we developed\Nit, was Dialogue: 0,0:02:40.25,0:02:42.95,Default,,0000,0000,0000,,we wanted to increase our performance. So,\Nso this Dialogue: 0,0:02:42.95,0:02:46.39,Default,,0000,0000,0000,,is like site performance. We, we had problems\Nwith Dialogue: 0,0:02:46.39,0:02:49.72,Default,,0000,0000,0000,,sort of abusive requests making our website\Nslow because Dialogue: 0,0:02:49.72,0:02:52.53,Default,,0000,0000,0000,,they were using up too many app servers CP. Dialogue: 0,0:02:52.53,0:02:54.50,Default,,0000,0000,0000,,Too much app server CPU, or too much, too Dialogue: 0,0:02:54.50,0:02:58.14,Default,,0000,0000,0000,,many database resources, by sort of constraining\Nthem we Dialogue: 0,0:02:58.14,0:03:00.61,Default,,0000,0000,0000,,were able to make the website faster for the Dialogue: 0,0:03:00.61,0:03:03.45,Default,,0000,0000,0000,,sort of, the most important requests. Like\Npeople coming Dialogue: 0,0:03:03.45,0:03:06.16,Default,,0000,0000,0000,,on, wanting to watch videos, wanting to pledge\Nmoney. Dialogue: 0,0:03:06.16,0:03:07.66,Default,,0000,0000,0000,,Not people just trying to scrape down the\Nentire Dialogue: 0,0:03:07.66,0:03:08.27,Default,,0000,0000,0000,,site. Dialogue: 0,0:03:08.27,0:03:11.94,Default,,0000,0000,0000,,We also improved our available. Because sometimes\Nthese requests Dialogue: 0,0:03:11.94,0:03:14.46,Default,,0000,0000,0000,,were, were so much, there were so many that Dialogue: 0,0:03:14.46,0:03:15.92,Default,,0000,0000,0000,,they would take down the site, or there would Dialogue: 0,0:03:15.92,0:03:19.86,Default,,0000,0000,0000,,just be some weird incident and, we, right.\NIt, Dialogue: 0,0:03:19.86,0:03:22.54,Default,,0000,0000,0000,,it hurt our availability. Dialogue: 0,0:03:22.54,0:03:25.84,Default,,0000,0000,0000,,But the biggest win that we had was developer Dialogue: 0,0:03:25.84,0:03:30.37,Default,,0000,0000,0000,,happiness. Because dealing with these sort\Nof bad actors Dialogue: 0,0:03:30.37,0:03:33.94,Default,,0000,0000,0000,,on the internet especially if it means, like,\Nyour, Dialogue: 0,0:03:33.94,0:03:35.97,Default,,0000,0000,0000,,your site's going down or like, the, you know, Dialogue: 0,0:03:35.97,0:03:38.96,Default,,0000,0000,0000,,you need to scale up because somebody's doing\Nsomething Dialogue: 0,0:03:38.96,0:03:41.75,Default,,0000,0000,0000,,weird, that can really interrupt a lot of\Ndevelopers. Dialogue: 0,0:03:41.75,0:03:44.23,Default,,0000,0000,0000,,It can, it can sort of derail your product Dialogue: 0,0:03:44.23,0:03:47.32,Default,,0000,0000,0000,,road map. We want to be writing cool features Dialogue: 0,0:03:47.32,0:03:50.19,Default,,0000,0000,0000,,and Rack::Attack was a great DSL to let us Dialogue: 0,0:03:50.19,0:03:53.33,Default,,0000,0000,0000,,spend less time thinking about that stuff\Nand more Dialogue: 0,0:03:53.33,0:03:54.85,Default,,0000,0000,0000,,stuff doing the stuff that we, that we like Dialogue: 0,0:03:54.85,0:03:55.43,Default,,0000,0000,0000,,doing. Dialogue: 0,0:03:55.43,0:03:58.96,Default,,0000,0000,0000,,So let me talk about the origin story for Dialogue: 0,0:03:58.96,0:04:01.26,Default,,0000,0000,0000,,Rack::Attack. Like, what happened at KickStarter\Nthat made us Dialogue: 0,0:04:01.26,0:04:05.06,Default,,0000,0000,0000,,realize we, we needed this? Let's rewind to\Nthe Dialogue: 0,0:04:05.06,0:04:10.79,Default,,0000,0000,0000,,summer of 2012. Dialogue: 0,0:04:10.79,0:04:12.51,Default,,0000,0000,0000,,And this happened. So this is a story in Dialogue: 0,0:04:12.51,0:04:15.93,Default,,0000,0000,0000,,a graph. So the blue line, I hope it Dialogue: 0,0:04:15.93,0:04:19.85,Default,,0000,0000,0000,,shows up pretty well. Cool. Is our regular\Nsuccessful Dialogue: 0,0:04:19.85,0:04:22.00,Default,,0000,0000,0000,,logins. People typing in an email and password\Nand Dialogue: 0,0:04:22.00,0:04:24.92,Default,,0000,0000,0000,,us being like, OK, you are logged in. You Dialogue: 0,0:04:24.92,0:04:26.83,Default,,0000,0000,0000,,know, it ebs and flows throughout the day. Dialogue: 0,0:04:26.83,0:04:30.62,Default,,0000,0000,0000,,Suddenly, one Sun, one Saturday afternoon,\Nwe just get Dialogue: 0,0:04:30.62,0:04:34.46,Default,,0000,0000,0000,,so many of these, like, bad login requests,\Nand Dialogue: 0,0:04:34.46,0:04:36.50,Default,,0000,0000,0000,,for awhile we're like, what's going on? Did\Nwe Dialogue: 0,0:04:36.50,0:04:39.22,Default,,0000,0000,0000,,deploy a feature that broke login? No. Somebody\Nis Dialogue: 0,0:04:39.22,0:04:42.09,Default,,0000,0000,0000,,trying to, to crack our user accounts. They're\Njust Dialogue: 0,0:04:42.09,0:04:45.47,Default,,0000,0000,0000,,like guessing email addresses and passwords\Nas fast as Dialogue: 0,0:04:45.47,0:04:48.85,Default,,0000,0000,0000,,they can, from several different IP addresses. Dialogue: 0,0:04:48.85,0:04:51.81,Default,,0000,0000,0000,,So, as the ops guy, this is sort of Dialogue: 0,0:04:51.81,0:04:54.00,Default,,0000,0000,0000,,on my plate. I'm like, OK, well, I gotta Dialogue: 0,0:04:54.00,0:04:55.56,Default,,0000,0000,0000,,stop this. This is bad for the site for Dialogue: 0,0:04:55.56,0:04:58.65,Default,,0000,0000,0000,,this to be going on. So I wrote a Dialogue: 0,0:04:58.65,0:05:01.74,Default,,0000,0000,0000,,pretty nasty before filter for our login action,\Nthat's Dialogue: 0,0:05:01.74,0:05:04.56,Default,,0000,0000,0000,,like, you know, keep a counter in memcache\Nand, Dialogue: 0,0:05:04.56,0:05:07.32,Default,,0000,0000,0000,,you know, if it's too many like, like, give Dialogue: 0,0:05:07.32,0:05:11.48,Default,,0000,0000,0000,,them an error page and it was, it was Dialogue: 0,0:05:11.48,0:05:14.63,Default,,0000,0000,0000,,kind of a sucky experience, because I was\Nchanging Dialogue: 0,0:05:14.63,0:05:17.48,Default,,0000,0000,0000,,a really critical feature of our site, sort\Nof Dialogue: 0,0:05:17.48,0:05:20.12,Default,,0000,0000,0000,,under duress of, of knowing that I needed\Nto Dialogue: 0,0:05:20.12,0:05:22.98,Default,,0000,0000,0000,,get it out there quickly. And it was sort Dialogue: 0,0:05:22.98,0:05:24.44,Default,,0000,0000,0000,,of like a big change, and in the pull Dialogue: 0,0:05:24.44,0:05:26.62,Default,,0000,0000,0000,,request I was, I was apologetic, being like,\NI Dialogue: 0,0:05:26.62,0:05:28.22,Default,,0000,0000,0000,,know this is badly tested and it's like a Dialogue: 0,0:05:28.22,0:05:29.85,Default,,0000,0000,0000,,nasty code change, but we've got to get it Dialogue: 0,0:05:29.85,0:05:33.70,Default,,0000,0000,0000,,out fast because this, this event's going\Non. Dialogue: 0,0:05:33.70,0:05:36.93,Default,,0000,0000,0000,,And, so that, so we did that. And then Dialogue: 0,0:05:36.93,0:05:39.68,Default,,0000,0000,0000,,sort of in the cold light of day, I Dialogue: 0,0:05:39.68,0:05:42.05,Default,,0000,0000,0000,,reflected a little bit and I thought, we need Dialogue: 0,0:05:42.05,0:05:47.44,Default,,0000,0000,0000,,a more elegant way to prevent bad requests.\NThis Dialogue: 0,0:05:47.44,0:05:50.28,Default,,0000,0000,0000,,is, it's not just gonna be about this login Dialogue: 0,0:05:50.28,0:05:51.67,Default,,0000,0000,0000,,attack. This is gonna be about a whole class Dialogue: 0,0:05:51.67,0:05:54.25,Default,,0000,0000,0000,,of problems that we might have on the site. Dialogue: 0,0:05:54.25,0:05:57.64,Default,,0000,0000,0000,,You know, I should say, too, with that login Dialogue: 0,0:05:57.64,0:06:00.31,Default,,0000,0000,0000,,attack, it was something that we sort of always Dialogue: 0,0:06:00.31,0:06:02.51,Default,,0000,0000,0000,,imagined that, like, oh yeah, of course we\Nshould, Dialogue: 0,0:06:02.51,0:06:05.02,Default,,0000,0000,0000,,like, throttle login requests. We just hadn't\Never gotten Dialogue: 0,0:06:05.02,0:06:06.67,Default,,0000,0000,0000,,around to it. You know, it was in our Dialogue: 0,0:06:06.67,0:06:09.77,Default,,0000,0000,0000,,ticketing system as like a low-priority someday\Nsomebody should Dialogue: 0,0:06:09.77,0:06:13.30,Default,,0000,0000,0000,,do this thing. And having it actually happen\Nwas Dialogue: 0,0:06:13.30,0:06:15.46,Default,,0000,0000,0000,,like, OK, now we gotta do it right now. Dialogue: 0,0:06:15.46,0:06:18.57,Default,,0000,0000,0000,,So, we realized, like, we need this generic\Ntool Dialogue: 0,0:06:18.57,0:06:23.81,Default,,0000,0000,0000,,to stop bad requests. And really, there's\Nalready, in Dialogue: 0,0:06:23.81,0:06:25.81,Default,,0000,0000,0000,,the Ruby world, a great solution for this,\Nand Dialogue: 0,0:06:25.81,0:06:29.34,Default,,0000,0000,0000,,it's Rack middleware. So now we get to the Dialogue: 0,0:06:29.34,0:06:32.02,Default,,0000,0000,0000,,code section of the talk. Here comes some\Ncode. Dialogue: 0,0:06:32.02,0:06:33.62,Default,,0000,0000,0000,,Get ready. Dialogue: 0,0:06:33.62,0:06:35.84,Default,,0000,0000,0000,,This is an example of, like, the most basic Dialogue: 0,0:06:35.84,0:06:38.19,Default,,0000,0000,0000,,Rack middleware. Just, really quick, for,\Nfor people who Dialogue: 0,0:06:38.19,0:06:41.39,Default,,0000,0000,0000,,might not be familiar with it. So middleware\Nis Dialogue: 0,0:06:41.39,0:06:45.65,Default,,0000,0000,0000,,basically like hugging your application, wrapping\Naround so, so Dialogue: 0,0:06:45.65,0:06:47.43,Default,,0000,0000,0000,,you, you have your Rails app or your Sinatra Dialogue: 0,0:06:47.43,0:06:52.35,Default,,0000,0000,0000,,app, that is the app in this case. And Dialogue: 0,0:06:52.35,0:06:53.94,Default,,0000,0000,0000,,you want to do things, you want to sort Dialogue: 0,0:06:53.94,0:06:56.44,Default,,0000,0000,0000,,of be able to do things to the request Dialogue: 0,0:06:56.44,0:06:58.59,Default,,0000,0000,0000,,that's coming in from the client. That's the\Nend. Dialogue: 0,0:06:58.59,0:07:01.56,Default,,0000,0000,0000,,So every, every request from a client is gonna Dialogue: 0,0:07:01.56,0:07:03.26,Default,,0000,0000,0000,,do this call method where you pass in the Dialogue: 0,0:07:03.26,0:07:06.05,Default,,0000,0000,0000,,environment, the environment is, like, I don't\Nknow, what Dialogue: 0,0:07:06.05,0:07:09.08,Default,,0000,0000,0000,,page the client wants or what they're cookie\Nis Dialogue: 0,0:07:09.08,0:07:11.71,Default,,0000,0000,0000,,and, and all that information. Dialogue: 0,0:07:11.71,0:07:14.46,Default,,0000,0000,0000,,And so the real magic of Rack middleware is Dialogue: 0,0:07:14.46,0:07:16.74,Default,,0000,0000,0000,,it lets you do stuff here with, with the Dialogue: 0,0:07:16.74,0:07:19.01,Default,,0000,0000,0000,,requests. Like, you can block it in the case Dialogue: 0,0:07:19.01,0:07:23.04,Default,,0000,0000,0000,,of Rack::Attack, potentially. Or you can do\Nstuff with Dialogue: 0,0:07:23.04,0:07:26.34,Default,,0000,0000,0000,,the response. You can log it. You can cache Dialogue: 0,0:07:26.34,0:07:27.57,Default,,0000,0000,0000,,it. Stuff like that. Dialogue: 0,0:07:27.57,0:07:29.02,Default,,0000,0000,0000,,So this, so this is just a great pattern Dialogue: 0,0:07:29.02,0:07:34.10,Default,,0000,0000,0000,,for managing, for sort of making easy architectures\Nto Dialogue: 0,0:07:34.10,0:07:38.63,Default,,0000,0000,0000,,do stuff with HTTP requests. So in Rack::Attack's\Ncase, Dialogue: 0,0:07:38.63,0:07:40.88,Default,,0000,0000,0000,,this is a sort of simplified version of the Dialogue: 0,0:07:40.88,0:07:45.44,Default,,0000,0000,0000,,Rack::Attack call method. We say, for this\Nrequest, should Dialogue: 0,0:07:45.44,0:07:47.89,Default,,0000,0000,0000,,we allow it? If so, go ahead and pass Dialogue: 0,0:07:47.89,0:07:51.89,Default,,0000,0000,0000,,it onto your application. Your application\Nis gonna do, Dialogue: 0,0:07:51.89,0:07:53.33,Default,,0000,0000,0000,,potentially, a lot of work. Dialogue: 0,0:07:53.33,0:07:55.96,Default,,0000,0000,0000,,Maybe it's gonna spend a couple hundred milliseconds,\Nlike, Dialogue: 0,0:07:55.96,0:07:59.30,Default,,0000,0000,0000,,querying the database and rendering views\Nand stuff like Dialogue: 0,0:07:59.30,0:08:01.91,Default,,0000,0000,0000,,that. So that's the expensive work that we\Nwant Dialogue: 0,0:08:01.91,0:08:05.15,Default,,0000,0000,0000,,to save if the, if this is an abusive Dialogue: 0,0:08:05.15,0:08:07.58,Default,,0000,0000,0000,,request. So, so if we shouldn't allow it,\Nthen Dialogue: 0,0:08:07.58,0:08:11.49,Default,,0000,0000,0000,,we just return back this very fast access-denied\Nas Dialogue: 0,0:08:11.49,0:08:14.57,Default,,0000,0000,0000,,a very simple and fast response to render. Dialogue: 0,0:08:14.57,0:08:18.50,Default,,0000,0000,0000,,Rack::Attack can do several hundred of these\Naccess denied Dialogue: 0,0:08:18.50,0:08:21.87,Default,,0000,0000,0000,,requests per, like, thread that you have running.\NSo Dialogue: 0,0:08:21.87,0:08:25.13,Default,,0000,0000,0000,,like, per unicorn worker or per Heroku instance\Nor Dialogue: 0,0:08:25.13,0:08:26.58,Default,,0000,0000,0000,,something like that. Dialogue: 0,0:08:26.58,0:08:29.87,Default,,0000,0000,0000,,But, so, that's what you get for, when you Dialogue: 0,0:08:29.87,0:08:32.40,Default,,0000,0000,0000,,just use the Rack middleware for free. So,\Nso Dialogue: 0,0:08:32.40,0:08:34.83,Default,,0000,0000,0000,,we don't yet know what this should_allow method\Nshould Dialogue: 0,0:08:34.83,0:08:36.42,Default,,0000,0000,0000,,be. That's code that you sort of have to Dialogue: 0,0:08:36.42,0:08:39.30,Default,,0000,0000,0000,,configure yourself, of what do you want to\Nthrottle Dialogue: 0,0:08:39.30,0:08:40.00,Default,,0000,0000,0000,,on. Dialogue: 0,0:08:40.00,0:08:43.23,Default,,0000,0000,0000,,So that looks like this. This is sort of Dialogue: 0,0:08:43.23,0:08:46.07,Default,,0000,0000,0000,,a generic throttle that you might put in your, Dialogue: 0,0:08:46.07,0:08:51.43,Default,,0000,0000,0000,,in an initializer to configure Rack::Attack.\NThe important stuff Dialogue: 0,0:08:51.43,0:08:53.30,Default,,0000,0000,0000,,that's going on here is we are calling the Dialogue: 0,0:08:53.30,0:08:57.09,Default,,0000,0000,0000,,throttle class method on Rack::Attack, so\Nthat's just something Dialogue: 0,0:08:57.09,0:09:00.20,Default,,0000,0000,0000,,we expose to let you plug into the middleware. Dialogue: 0,0:09:00.20,0:09:02.15,Default,,0000,0000,0000,,We give it a name, in this case it's Dialogue: 0,0:09:02.15,0:09:04.95,Default,,0000,0000,0000,,the, we, we named the throttle IP. This is Dialogue: 0,0:09:04.95,0:09:08.08,Default,,0000,0000,0000,,gonna determine how we track it. And that\Njust Dialogue: 0,0:09:08.08,0:09:11.21,Default,,0000,0000,0000,,has to be unique throughout your application.\NWe're gonna Dialogue: 0,0:09:11.21,0:09:13.14,Default,,0000,0000,0000,,give it a limit and a period. And so Dialogue: 0,0:09:13.14,0:09:15.65,Default,,0000,0000,0000,,that's how much, the, the period is how many Dialogue: 0,0:09:15.65,0:09:18.48,Default,,0000,0000,0000,,seconds we're gonna be considering for the\Nthrottle, and Dialogue: 0,0:09:18.48,0:09:20.39,Default,,0000,0000,0000,,the limit is sort of your quota for how Dialogue: 0,0:09:20.39,0:09:23.18,Default,,0000,0000,0000,,many requests you get to make during that\Ntime. Dialogue: 0,0:09:23.18,0:09:25.32,Default,,0000,0000,0000,,So in this case, it's ten requests every five Dialogue: 0,0:09:25.32,0:09:30.92,Default,,0000,0000,0000,,seconds. For the arithmetically inclined,\Nyou'll notice that this Dialogue: 0,0:09:30.92,0:09:33.63,Default,,0000,0000,0000,,is not like a reduced fraction. We could say Dialogue: 0,0:09:33.63,0:09:37.04,Default,,0000,0000,0000,,two requests every one second. The advantage\Nof doing Dialogue: 0,0:09:37.04,0:09:38.79,Default,,0000,0000,0000,,a higher multiple is that, like, it allows\Na Dialogue: 0,0:09:38.79,0:09:42.65,Default,,0000,0000,0000,,little burstiness. So these periods are basically\Ndividing time Dialogue: 0,0:09:42.65,0:09:46.21,Default,,0000,0000,0000,,up into these, like, five second long buckets.\NSo Dialogue: 0,0:09:46.21,0:09:49.40,Default,,0000,0000,0000,,in between zero and, seconds and five seconds\Nafter Dialogue: 0,0:09:49.40,0:09:51.94,Default,,0000,0000,0000,,the minute, like, in that window, you're allowed\Nto Dialogue: 0,0:09:51.94,0:09:54.20,Default,,0000,0000,0000,,make up to ten requests. Dialogue: 0,0:09:54.20,0:09:57.66,Default,,0000,0000,0000,,And so by having bigger multiples in bigger\Nwindows, Dialogue: 0,0:09:57.66,0:10:00.84,Default,,0000,0000,0000,,you can sort of get around some burstiness\Nat, Dialogue: 0,0:10:00.84,0:10:03.74,Default,,0000,0000,0000,,but the long-term average stays the same.\NLike, long Dialogue: 0,0:10:03.74,0:10:07.30,Default,,0000,0000,0000,,term, nobody's gonna make more requests that\Ntwo every Dialogue: 0,0:10:07.30,0:10:09.24,Default,,0000,0000,0000,,one second. Dialogue: 0,0:10:09.24,0:10:12.14,Default,,0000,0000,0000,,OK, so what's going on? We got the, the Dialogue: 0,0:10:12.14,0:10:14.69,Default,,0000,0000,0000,,class method. We got the name. WE have the Dialogue: 0,0:10:14.69,0:10:17.39,Default,,0000,0000,0000,,limit and the period. And then to this block, Dialogue: 0,0:10:17.39,0:10:20.73,Default,,0000,0000,0000,,we are passing along the request. Now, in\Nthe Dialogue: 0,0:10:20.73,0:10:23.32,Default,,0000,0000,0000,,earlier middleware expample we talked, we\Ncalled this the Dialogue: 0,0:10:23.32,0:10:25.83,Default,,0000,0000,0000,,end, which was just like the, the environment\Nhash Dialogue: 0,0:10:25.83,0:10:29.24,Default,,0000,0000,0000,,that comes from the request. Request is just\Nlike Dialogue: 0,0:10:29.24,0:10:33.74,Default,,0000,0000,0000,,a light little Rack request object wrapped\Naround the Dialogue: 0,0:10:33.74,0:10:36.77,Default,,0000,0000,0000,,environment that just sort of gives you methods,\Ninstance Dialogue: 0,0:10:36.77,0:10:39.51,Default,,0000,0000,0000,,methods to call, like dot IP or dot host Dialogue: 0,0:10:39.51,0:10:41.17,Default,,0000,0000,0000,,or dot path or something like that. It just Dialogue: 0,0:10:41.17,0:10:46.15,Default,,0000,0000,0000,,sort of, you use these in Rails controllers,\Ntoo. Dialogue: 0,0:10:46.15,0:10:49.82,Default,,0000,0000,0000,,So it's just like a lightly-wrapped request.\NAnd then Dialogue: 0,0:10:49.82,0:10:52.10,Default,,0000,0000,0000,,inside the block, what the block returns is\Nthe Dialogue: 0,0:10:52.10,0:10:54.64,Default,,0000,0000,0000,,sort of really important part. That's the\Ndiscriminator that Dialogue: 0,0:10:54.64,0:10:58.14,Default,,0000,0000,0000,,determines how we're gonna bucket up these\Nthrottles. So Dialogue: 0,0:10:58.14,0:11:00.93,Default,,0000,0000,0000,,in this case we are gonna say every IP Dialogue: 0,0:11:00.93,0:11:03.65,Default,,0000,0000,0000,,address, every distinct IP address is going\Nto get Dialogue: 0,0:11:03.65,0:11:06.83,Default,,0000,0000,0000,,its own throttle limit. But we could throttle\Nby Dialogue: 0,0:11:06.83,0:11:09.62,Default,,0000,0000,0000,,something else. WE could throttle by a parameter\Nor Dialogue: 0,0:11:09.62,0:11:14.46,Default,,0000,0000,0000,,a host name or something like that, or an Dialogue: 0,0:11:14.46,0:11:16.13,Default,,0000,0000,0000,,API token. Dialogue: 0,0:11:16.13,0:11:18.49,Default,,0000,0000,0000,,And one thing to note with these discriminators,\Ntoo, Dialogue: 0,0:11:18.49,0:11:21.46,Default,,0000,0000,0000,,is like, if this would, this is returning\Na Dialogue: 0,0:11:21.46,0:11:24.05,Default,,0000,0000,0000,,string, so it's always gonna be a truthy value, Dialogue: 0,0:11:24.05,0:11:26.70,Default,,0000,0000,0000,,and true values sort of enable the, the throttling. Dialogue: 0,0:11:26.70,0:11:29.03,Default,,0000,0000,0000,,Like, we are gonna throttle these requests\Nas long Dialogue: 0,0:11:29.03,0:11:32.19,Default,,0000,0000,0000,,as there's an IP address, and there always\Nis. Dialogue: 0,0:11:32.19,0:11:34.67,Default,,0000,0000,0000,,If we would return nil or a falsey value, Dialogue: 0,0:11:34.67,0:11:36.54,Default,,0000,0000,0000,,we just sort of let the request go through Dialogue: 0,0:11:36.54,0:11:38.74,Default,,0000,0000,0000,,and we're not gonna throttle it. I'll talk\Nabout Dialogue: 0,0:11:38.74,0:11:41.79,Default,,0000,0000,0000,,why we might want to do that later. But, Dialogue: 0,0:11:41.79,0:11:43.71,Default,,0000,0000,0000,,so now we have this issue of throttle state. Dialogue: 0,0:11:43.71,0:11:46.42,Default,,0000,0000,0000,,Like, we have these counters per IP address\Nthat Dialogue: 0,0:11:46.42,0:11:48.32,Default,,0000,0000,0000,,we need to track. Dialogue: 0,0:11:48.32,0:11:50.56,Default,,0000,0000,0000,,And so, so where do we store that? A Dialogue: 0,0:11:50.56,0:11:53.12,Default,,0000,0000,0000,,pretty elegant and simple and obvious place\Nfor that Dialogue: 0,0:11:53.12,0:11:56.88,Default,,0000,0000,0000,,was our Rails cache. So when you just use Dialogue: 0,0:11:56.88,0:11:59.10,Default,,0000,0000,0000,,Rack::Attack by default, if you have a Rails\Ncache, Dialogue: 0,0:11:59.10,0:12:02.45,Default,,0000,0000,0000,,it's gonna use it. But, it really works best Dialogue: 0,0:12:02.45,0:12:05.78,Default,,0000,0000,0000,,with memcache or redis. So, so I hope you're Dialogue: 0,0:12:05.78,0:12:09.05,Default,,0000,0000,0000,,using that as your Rails cache. But if you're Dialogue: 0,0:12:09.05,0:12:10.89,Default,,0000,0000,0000,,not, like, there are ways that you can build Dialogue: 0,0:12:10.89,0:12:12.51,Default,,0000,0000,0000,,your own, or sort of like plug in a, Dialogue: 0,0:12:12.51,0:12:14.67,Default,,0000,0000,0000,,a different cache store. Dialogue: 0,0:12:14.67,0:12:17.07,Default,,0000,0000,0000,,The great advantage about memcache and redis\Nis that Dialogue: 0,0:12:17.07,0:12:21.21,Default,,0000,0000,0000,,they have really good support for atomically\Nincrementing counters, Dialogue: 0,0:12:21.21,0:12:22.72,Default,,0000,0000,0000,,and that's the sort of key feature we'd need Dialogue: 0,0:12:22.72,0:12:26.27,Default,,0000,0000,0000,,behind the scenes. So now we're imagining\Nfor, for Dialogue: 0,0:12:26.27,0:12:28.21,Default,,0000,0000,0000,,every request that comes in, we need to sort Dialogue: 0,0:12:28.21,0:12:31.05,Default,,0000,0000,0000,,of increment the counter per IP address. Dialogue: 0,0:12:31.05,0:12:32.37,Default,,0000,0000,0000,,And so how do we do that? Like what's, Dialogue: 0,0:12:32.37,0:12:35.25,Default,,0000,0000,0000,,what's the algorithm? So this is the nitty\Ngritty Dialogue: 0,0:12:35.25,0:12:40.10,Default,,0000,0000,0000,,of how Rack::Attack works. How it constructs\Nthat key. Dialogue: 0,0:12:40.10,0:12:43.06,Default,,0000,0000,0000,,So remember how we divided the minute up into Dialogue: 0,0:12:43.06,0:12:46.81,Default,,0000,0000,0000,,like little buckets depending on our period.\NSo, so Dialogue: 0,0:12:46.81,0:12:48.79,Default,,0000,0000,0000,,to do that, we sort of take the current Dialogue: 0,0:12:48.79,0:12:53.62,Default,,0000,0000,0000,,second. We construct a key that is the name Dialogue: 0,0:12:53.62,0:12:57.38,Default,,0000,0000,0000,,of our request, like IP in this case. We Dialogue: 0,0:12:57.38,0:12:59.49,Default,,0000,0000,0000,,take the time divided by the period, so this Dialogue: 0,0:12:59.49,0:13:02.66,Default,,0000,0000,0000,,means that that middle component is going\Nto be, Dialogue: 0,0:13:02.66,0:13:05.35,Default,,0000,0000,0000,,is going to increment every five seconds.\NIt's gonna, Dialogue: 0,0:13:05.35,0:13:07.57,Default,,0000,0000,0000,,so it's, the key's gonna change. Dialogue: 0,0:13:07.57,0:13:09.36,Default,,0000,0000,0000,,And then the final part is that block return Dialogue: 0,0:13:09.36,0:13:12.17,Default,,0000,0000,0000,,value. So in this case it's the IP address Dialogue: 0,0:13:12.17,0:13:15.15,Default,,0000,0000,0000,,of the request. But maybe it's an API token Dialogue: 0,0:13:15.15,0:13:17.17,Default,,0000,0000,0000,,or something like that. Dialogue: 0,0:13:17.17,0:13:18.72,Default,,0000,0000,0000,,So at the end of it, we have this Dialogue: 0,0:13:18.72,0:13:21.99,Default,,0000,0000,0000,,key that changes every couple seconds. Every\Ntime, like, Dialogue: 0,0:13:21.99,0:13:24.72,Default,,0000,0000,0000,,the period rotates, and this ends up being\Na Dialogue: 0,0:13:24.72,0:13:27.45,Default,,0000,0000,0000,,very efficient use case, a very efficient\Nuse of Dialogue: 0,0:13:27.45,0:13:30.88,Default,,0000,0000,0000,,memcache or redis. Like, this is, storing\Nall this Dialogue: 0,0:13:30.88,0:13:34.01,Default,,0000,0000,0000,,information is gonna take, like, a couple\Nmegabytes. It's Dialogue: 0,0:13:34.01,0:13:36.00,Default,,0000,0000,0000,,like, don't worry about the impact on your\Ncache Dialogue: 0,0:13:36.00,0:13:39.10,Default,,0000,0000,0000,,store in pretty much every scenario. Dialogue: 0,0:13:39.10,0:13:41.34,Default,,0000,0000,0000,,To make it even more efficient use of your Dialogue: 0,0:13:41.34,0:13:45.91,Default,,0000,0000,0000,,cache store, we set an expire rate, so that Dialogue: 0,0:13:45.91,0:13:48.11,Default,,0000,0000,0000,,in that, like, in that bucket window of, say, Dialogue: 0,0:13:48.11,0:13:50.42,Default,,0000,0000,0000,,zero to five seconds, we're gonna say that\Nall Dialogue: 0,0:13:50.42,0:13:53.10,Default,,0000,0000,0000,,those cache keys expire at five seconds. So\Nat Dialogue: 0,0:13:53.10,0:13:56.99,Default,,0000,0000,0000,,the same moment that the cache keys change,\Nthey Dialogue: 0,0:13:56.99,0:13:59.68,Default,,0000,0000,0000,,also expire. So memcache or redis just ends\Nup Dialogue: 0,0:13:59.68,0:14:03.20,Default,,0000,0000,0000,,reusing the same memory blocks over and over.\NYou Dialogue: 0,0:14:03.20,0:14:06.34,Default,,0000,0000,0000,,don't have, even though there's changing,\Nthey're changing in Dialogue: 0,0:14:06.34,0:14:08.40,Default,,0000,0000,0000,,memory, you don't have as much churn as you Dialogue: 0,0:14:08.40,0:14:11.30,Default,,0000,0000,0000,,would otherwise. Dialogue: 0,0:14:11.30,0:14:13.89,Default,,0000,0000,0000,,And so then the Rack middleware is really\Ndoing Dialogue: 0,0:14:13.89,0:14:16.31,Default,,0000,0000,0000,,pretty simple stuff of we're saying, for whatever\Nyour Dialogue: 0,0:14:16.31,0:14:19.87,Default,,0000,0000,0000,,cache is, increment this key with this expire\Nrate. Dialogue: 0,0:14:19.87,0:14:21.46,Default,,0000,0000,0000,,That's gonna give us back the count of how Dialogue: 0,0:14:21.46,0:14:23.61,Default,,0000,0000,0000,,many requests that have been made that, that\Nmatch Dialogue: 0,0:14:23.61,0:14:26.61,Default,,0000,0000,0000,,that throttle. And if it's more than our limit, Dialogue: 0,0:14:26.61,0:14:29.68,Default,,0000,0000,0000,,we're gonna return that access denied response. Dialogue: 0,0:14:29.68,0:14:32.75,Default,,0000,0000,0000,,So, we rolled this out. You know, we're able Dialogue: 0,0:14:32.75,0:14:36.92,Default,,0000,0000,0000,,to have this global throttle per IP address.\NWe Dialogue: 0,0:14:36.92,0:14:40.78,Default,,0000,0000,0000,,start making a couple other, other features,\Nand it Dialogue: 0,0:14:40.78,0:14:44.03,Default,,0000,0000,0000,,was about a year later when we had a, Dialogue: 0,0:14:44.03,0:14:46.93,Default,,0000,0000,0000,,the sort of redux of, of a new event Dialogue: 0,0:14:46.93,0:14:48.98,Default,,0000,0000,0000,,that put Rack::Attack to the test. Dialogue: 0,0:14:48.98,0:14:52.04,Default,,0000,0000,0000,,So, a new challenger emerges in the summer\Nof Dialogue: 0,0:14:52.04,0:14:57.90,Default,,0000,0000,0000,,2013. This was a script called kicksniper\Ndot py. Dialogue: 0,0:14:57.90,0:15:02.08,Default,,0000,0000,0000,,And this revealed a pretty interesting behavior\Non KickStarter Dialogue: 0,0:15:02.08,0:15:05.29,Default,,0000,0000,0000,,that we call reward sniping. Actually, kicksniper\Ndot py Dialogue: 0,0:15:05.29,0:15:08.79,Default,,0000,0000,0000,,refers to it in the code as reward sniping. Dialogue: 0,0:15:08.79,0:15:12.11,Default,,0000,0000,0000,,And so, this is, this is an, an interesting Dialogue: 0,0:15:12.11,0:15:14.92,Default,,0000,0000,0000,,behavior because. So I told you how KickStarter\Noffers Dialogue: 0,0:15:14.92,0:15:17.80,Default,,0000,0000,0000,,these rewards. They can be limited rewards.\NSo a Dialogue: 0,0:15:17.80,0:15:20.17,Default,,0000,0000,0000,,creator says, I'm only gonna give away, like,\Na Dialogue: 0,0:15:20.17,0:15:24.12,Default,,0000,0000,0000,,hundred of these, and first come, first serve. Dialogue: 0,0:15:24.12,0:15:26.98,Default,,0000,0000,0000,,So, there's a, a pretty popular project where\Nit Dialogue: 0,0:15:26.98,0:15:28.70,Default,,0000,0000,0000,,was like a video game and, and the video Dialogue: 0,0:15:28.70,0:15:31.75,Default,,0000,0000,0000,,game was offering these reward tiers that\Nwould be, Dialogue: 0,0:15:31.75,0:15:33.98,Default,,0000,0000,0000,,like, for fifty bucks, you get, like, the\Nsilver Dialogue: 0,0:15:33.98,0:15:35.79,Default,,0000,0000,0000,,level package, and for a hundred bucks you\Nget Dialogue: 0,0:15:35.79,0:15:37.60,Default,,0000,0000,0000,,the gold package, and so on and so, like, Dialogue: 0,0:15:37.60,0:15:41.46,Default,,0000,0000,0000,,ever more deluxe and expensive packages. And\Nthey were Dialogue: 0,0:15:41.46,0:15:42.72,Default,,0000,0000,0000,,all very much in demand. Dialogue: 0,0:15:42.72,0:15:47.23,Default,,0000,0000,0000,,So the early reward tiers like sold-out super\Nfast. Dialogue: 0,0:15:47.23,0:15:50.09,Default,,0000,0000,0000,,And then occasionally, somebody in, who had\Nthose early Dialogue: 0,0:15:50.09,0:15:53.07,Default,,0000,0000,0000,,reward tiers, would decide they're gonna splurge\Nand they're Dialogue: 0,0:15:53.07,0:15:54.87,Default,,0000,0000,0000,,gonna upgrade. They're gonna change their\Npledge to a Dialogue: 0,0:15:54.87,0:15:58.60,Default,,0000,0000,0000,,higher one, and now for that moment, like,\Nthere's Dialogue: 0,0:15:58.60,0:16:01.43,Default,,0000,0000,0000,,now one available of the lower tier. And so Dialogue: 0,0:16:01.43,0:16:04.98,Default,,0000,0000,0000,,people were like hitting refresh, refresh,\Nrefresh, hoping that Dialogue: 0,0:16:04.98,0:16:07.77,Default,,0000,0000,0000,,they just noticed when somebody, when somebody\Nhad changed Dialogue: 0,0:16:07.77,0:16:09.35,Default,,0000,0000,0000,,their pledge and now there was one of these Dialogue: 0,0:16:09.35,0:16:12.41,Default,,0000,0000,0000,,highly desirable lower-tier pledges available. Dialogue: 0,0:16:12.41,0:16:18.42,Default,,0000,0000,0000,,Some entrepreneur, enterprising Python developer,\Nsays, I will make Dialogue: 0,0:16:18.42,0:16:21.96,Default,,0000,0000,0000,,a script that does this for me. Sure enough, Dialogue: 0,0:16:21.96,0:16:24.94,Default,,0000,0000,0000,,so, so he writes kicksniper dot py that's,\Nthat's Dialogue: 0,0:16:24.94,0:16:27.02,Default,,0000,0000,0000,,in a tight loop, trying to change his pledge Dialogue: 0,0:16:27.02,0:16:29.09,Default,,0000,0000,0000,,on our site. Saying, like, let me get that, Dialogue: 0,0:16:29.09,0:16:32.26,Default,,0000,0000,0000,,that early reward tier. You know, our ActiveRecord\Nvalidations Dialogue: 0,0:16:32.26,0:16:34.05,Default,,0000,0000,0000,,were working fine and we said, no, you can't Dialogue: 0,0:16:34.05,0:16:36.47,Default,,0000,0000,0000,,change your pledge to that the vast majority\Nof Dialogue: 0,0:16:36.47,0:16:39.73,Default,,0000,0000,0000,,the time, but, but eventually he got through\Nand Dialogue: 0,0:16:39.73,0:16:41.10,Default,,0000,0000,0000,,was able to get the pledge. Dialogue: 0,0:16:41.10,0:16:43.09,Default,,0000,0000,0000,,It was such a great success that he goes Dialogue: 0,0:16:43.09,0:16:45.89,Default,,0000,0000,0000,,on all the forums and says, hey, everybody\Njust Dialogue: 0,0:16:45.89,0:16:50.74,Default,,0000,0000,0000,,run this, like, Python script on your laptop\Nand Dialogue: 0,0:16:50.74,0:16:53.30,Default,,0000,0000,0000,,you, too, might look, luck out and get one Dialogue: 0,0:16:53.30,0:16:56.22,Default,,0000,0000,0000,,of these highly desirable earlier reward tiers. Dialogue: 0,0:16:56.22,0:17:01.36,Default,,0000,0000,0000,,So let's tell this story in a graph. So, Dialogue: 0,0:17:01.36,0:17:04.09,Default,,0000,0000,0000,,this is our master database CPU over the course Dialogue: 0,0:17:04.09,0:17:05.93,Default,,0000,0000,0000,,of a, of a day or so. We see Dialogue: 0,0:17:05.93,0:17:07.92,Default,,0000,0000,0000,,at the very beginning, it starts off between\Nten Dialogue: 0,0:17:07.92,0:17:10.76,Default,,0000,0000,0000,,or fifteen percent. That's my happy place.\NThat's where Dialogue: 0,0:17:10.76,0:17:12.04,Default,,0000,0000,0000,,I like it to be. We have plenty of Dialogue: 0,0:17:12.04,0:17:15.15,Default,,0000,0000,0000,,head room for like, you know, big projects\Nto Dialogue: 0,0:17:15.15,0:17:16.95,Default,,0000,0000,0000,,sort of blow up on the site, as they Dialogue: 0,0:17:16.95,0:17:18.98,Default,,0000,0000,0000,,do from time to time. Dialogue: 0,0:17:18.98,0:17:21.49,Default,,0000,0000,0000,,And, I honestly didn't really notice that\Nit had Dialogue: 0,0:17:21.49,0:17:24.34,Default,,0000,0000,0000,,been creeping up over the course of the day. Dialogue: 0,0:17:24.34,0:17:28.00,Default,,0000,0000,0000,,Thursday morning, it crossed thirty percent,\Nand that's when Dialogue: 0,0:17:28.00,0:17:30.94,Default,,0000,0000,0000,,I get a CPU alert threshold. So it, so Dialogue: 0,0:17:30.94,0:17:32.59,Default,,0000,0000,0000,,in fact, the whole dev team gets this email Dialogue: 0,0:17:32.59,0:17:34.91,Default,,0000,0000,0000,,being like, hey, the master database CPU is\Npretty Dialogue: 0,0:17:34.91,0:17:37.26,Default,,0000,0000,0000,,high. You guys should check that out. Dialogue: 0,0:17:37.26,0:17:41.32,Default,,0000,0000,0000,,So, what do we, you know, we, we spend Dialogue: 0,0:17:41.32,0:17:43.07,Default,,0000,0000,0000,,a little time, we're like, why is the database Dialogue: 0,0:17:43.07,0:17:44.87,Default,,0000,0000,0000,,so high? Well, you know, it looks like there Dialogue: 0,0:17:44.87,0:17:46.87,Default,,0000,0000,0000,,are a crazy number of requests trying to change Dialogue: 0,0:17:46.87,0:17:49.60,Default,,0000,0000,0000,,their pledge for this one project. Dialogue: 0,0:17:49.60,0:17:52.65,Default,,0000,0000,0000,,We, we're able to sort of construct this back Dialogue: 0,0:17:52.65,0:17:54.53,Default,,0000,0000,0000,,story and, like, see what was happening on\Nthe Dialogue: 0,0:17:54.53,0:17:57.09,Default,,0000,0000,0000,,database CPU. We see the form request where\Neverybody's Dialogue: 0,0:17:57.09,0:18:02.28,Default,,0000,0000,0000,,like, thank you for kicksniper dot py. And\Nso, Dialogue: 0,0:18:02.28,0:18:03.92,Default,,0000,0000,0000,,and we're like, all right, so, so how are Dialogue: 0,0:18:03.92,0:18:06.39,Default,,0000,0000,0000,,we gonna handle this? Like, is it really that Dialogue: 0,0:18:06.39,0:18:08.99,Default,,0000,0000,0000,,important that people are able to try to change Dialogue: 0,0:18:08.99,0:18:11.40,Default,,0000,0000,0000,,their pledge like multiple times a second? Dialogue: 0,0:18:11.40,0:18:13.50,Default,,0000,0000,0000,,What if they only could change their pledge\Nevery Dialogue: 0,0:18:13.50,0:18:17.05,Default,,0000,0000,0000,,couple seconds? Right, like, I guess that's\Nfair enough Dialogue: 0,0:18:17.05,0:18:19.13,Default,,0000,0000,0000,,to the, like, there's this question of, like,\Nwhat's Dialogue: 0,0:18:19.13,0:18:22.03,Default,,0000,0000,0000,,the fairest way to allocate the scarce resources\Nof, Dialogue: 0,0:18:22.03,0:18:24.50,Default,,0000,0000,0000,,of like the pledge as soon as it's available. Dialogue: 0,0:18:24.50,0:18:26.72,Default,,0000,0000,0000,,I kind of don't care about the answer. Anybody Dialogue: 0,0:18:26.72,0:18:28.45,Default,,0000,0000,0000,,can get it. Dialogue: 0,0:18:28.45,0:18:32.41,Default,,0000,0000,0000,,But, but we're like, if we start throttling\Nthese Dialogue: 0,0:18:32.41,0:18:34.60,Default,,0000,0000,0000,,people, it's like totally fair. They're using\Nan inordinate Dialogue: 0,0:18:34.60,0:18:37.54,Default,,0000,0000,0000,,number of resources. And people who are just\Nclicking Dialogue: 0,0:18:37.54,0:18:40.04,Default,,0000,0000,0000,,around the site are having a slower experience\Nbecause Dialogue: 0,0:18:40.04,0:18:42.40,Default,,0000,0000,0000,,our database CPU is so high. Dialogue: 0,0:18:42.40,0:18:44.02,Default,,0000,0000,0000,,So we decide, like, OK, you can make a Dialogue: 0,0:18:44.02,0:18:46.25,Default,,0000,0000,0000,,couple requests per minute to change a pledge.\NIt Dialogue: 0,0:18:46.25,0:18:49.86,Default,,0000,0000,0000,,was one line of Rack::Attack code. We deploy\Nit. Dialogue: 0,0:18:49.86,0:18:52.19,Default,,0000,0000,0000,,The yellow vertical lines here are deploy\Nlines, so Dialogue: 0,0:18:52.19,0:18:55.21,Default,,0000,0000,0000,,you can see that right here, about an hour Dialogue: 0,0:18:55.21,0:18:57.25,Default,,0000,0000,0000,,after we get the alert that something was\Ngoing Dialogue: 0,0:18:57.25,0:19:01.71,Default,,0000,0000,0000,,wrong, we deploy and immediately our database\NCPU drops. Dialogue: 0,0:19:01.71,0:19:04.78,Default,,0000,0000,0000,,We're pretty much back to the happy place. Dialogue: 0,0:19:04.78,0:19:07.64,Default,,0000,0000,0000,,And so, for us, that was like, revealing the, Dialogue: 0,0:19:07.64,0:19:09.24,Default,,0000,0000,0000,,the great success that we could have. Like,\Nit Dialogue: 0,0:19:09.24,0:19:12.00,Default,,0000,0000,0000,,was so easy, like, once we figured out what Dialogue: 0,0:19:12.00,0:19:14.47,Default,,0000,0000,0000,,was going on, it was so easy for us Dialogue: 0,0:19:14.47,0:19:17.10,Default,,0000,0000,0000,,to write code that just, like, solved that\Nproblem. Dialogue: 0,0:19:17.10,0:19:19.03,Default,,0000,0000,0000,,We didn't have to think about, like, how do Dialogue: 0,0:19:19.03,0:19:23.33,Default,,0000,0000,0000,,we optimize the edit pledge flow? Which could\Nhave Dialogue: 0,0:19:23.33,0:19:26.26,Default,,0000,0000,0000,,been, like, a much bigger product change,\Nand derail, Dialogue: 0,0:19:26.26,0:19:28.09,Default,,0000,0000,0000,,like, taken up a lot more developer time.\NIt Dialogue: 0,0:19:28.09,0:19:30.32,Default,,0000,0000,0000,,was sort of a cut and dry decision of Dialogue: 0,0:19:30.32,0:19:32.80,Default,,0000,0000,0000,,like, most people aren't gonna try to change\Ntheir Dialogue: 0,0:19:32.80,0:19:35.02,Default,,0000,0000,0000,,pledge, like, we're super confused if you're\Nactually trying Dialogue: 0,0:19:35.02,0:19:36.91,Default,,0000,0000,0000,,to change your pledge several times a minute. Dialogue: 0,0:19:36.91,0:19:39.29,Default,,0000,0000,0000,,That's a, that's a bug we should fix. But Dialogue: 0,0:19:39.29,0:19:41.36,Default,,0000,0000,0000,,it's really just these scrapers. It's not\Nbig deal Dialogue: 0,0:19:41.36,0:19:43.04,Default,,0000,0000,0000,,to say they can try a few times a Dialogue: 0,0:19:43.04,0:19:43.45,Default,,0000,0000,0000,,minute. Dialogue: 0,0:19:43.45,0:19:47.47,Default,,0000,0000,0000,,So, that was a big win for Rack::Attack at Dialogue: 0,0:19:47.47,0:19:50.11,Default,,0000,0000,0000,,KickStarter. We feel like we sort of, we sort Dialogue: 0,0:19:50.11,0:19:54.23,Default,,0000,0000,0000,,of cemented that its value in the organization.\NSo Dialogue: 0,0:19:54.23,0:19:56.25,Default,,0000,0000,0000,,now I'm gonna shift gears a little bit and Dialogue: 0,0:19:56.25,0:19:59.50,Default,,0000,0000,0000,,I'm gonna tell you pro tips of general things Dialogue: 0,0:19:59.50,0:20:01.82,Default,,0000,0000,0000,,you can do with Rack::Attack that, that are\Nprobably Dialogue: 0,0:20:01.82,0:20:03.21,Default,,0000,0000,0000,,useful for your application. Dialogue: 0,0:20:03.21,0:20:07.04,Default,,0000,0000,0000,,I just, oh my gosh I'm so glad that Dialogue: 0,0:20:07.04,0:20:08.41,Default,,0000,0000,0000,,I got to use this gif. This gif is Dialogue: 0,0:20:08.41,0:20:12.58,Default,,0000,0000,0000,,like condensed, pure condensed happiness for\Nme. OK. Back Dialogue: 0,0:20:12.58,0:20:14.32,Default,,0000,0000,0000,,to the code. Dialogue: 0,0:20:14.32,0:20:16.90,Default,,0000,0000,0000,,So, we talked about how to do, like, a Dialogue: 0,0:20:16.90,0:20:20.13,Default,,0000,0000,0000,,general, a, a log, I'm sorry. We talked about Dialogue: 0,0:20:20.13,0:20:24.18,Default,,0000,0000,0000,,how to do a throttle for all IP addresses. Dialogue: 0,0:20:24.18,0:20:25.77,Default,,0000,0000,0000,,So like each IP has this quota of how Dialogue: 0,0:20:25.77,0:20:28.71,Default,,0000,0000,0000,,many requests you can do. But, in our, in Dialogue: 0,0:20:28.71,0:20:32.50,Default,,0000,0000,0000,,our origin story about the login attack, we\Nwanted Dialogue: 0,0:20:32.50,0:20:35.38,Default,,0000,0000,0000,,to be extra careful about login requests.\NLike, those Dialogue: 0,0:20:35.38,0:20:38.17,Default,,0000,0000,0000,,are something that, that you would want to\Nthrottle Dialogue: 0,0:20:38.17,0:20:40.88,Default,,0000,0000,0000,,even more strictly than you would throttle\Nmany other Dialogue: 0,0:20:40.88,0:20:43.73,Default,,0000,0000,0000,,things on your, in your application. Dialogue: 0,0:20:43.73,0:20:46.86,Default,,0000,0000,0000,,So this is a new throttle, and so we Dialogue: 0,0:20:46.86,0:20:49.59,Default,,0000,0000,0000,,give it a new name of logins per IP. Dialogue: 0,0:20:49.59,0:20:52.02,Default,,0000,0000,0000,,And this is saying that if you are making Dialogue: 0,0:20:52.02,0:20:55.53,Default,,0000,0000,0000,,a post request to the login url, then we Dialogue: 0,0:20:55.53,0:20:57.66,Default,,0000,0000,0000,,want to throttle you by IP to like this Dialogue: 0,0:20:57.66,0:21:01.60,Default,,0000,0000,0000,,much, this lower limit. And so this is relying Dialogue: 0,0:21:01.60,0:21:04.52,Default,,0000,0000,0000,,on the fact that we mentioned earlier, that\Nif Dialogue: 0,0:21:04.52,0:21:06.83,Default,,0000,0000,0000,,the block returns nil, we're not gonna do\Nthrottle Dialogue: 0,0:21:06.83,0:21:08.76,Default,,0000,0000,0000,,at all. So, so if this is not a Dialogue: 0,0:21:08.76,0:21:11.74,Default,,0000,0000,0000,,post to the login action, like, we're not\Ngonna Dialogue: 0,0:21:11.74,0:21:14.20,Default,,0000,0000,0000,,check memcache, we're not gonna increment\Nany counters or Dialogue: 0,0:21:14.20,0:21:15.73,Default,,0000,0000,0000,,do anything like that. We're just gonna sort\Nof Dialogue: 0,0:21:15.73,0:21:18.59,Default,,0000,0000,0000,,allow this request right through. Dialogue: 0,0:21:18.59,0:21:20.40,Default,,0000,0000,0000,,But if it is, we're gonna hold you, we're Dialogue: 0,0:21:20.40,0:21:22.83,Default,,0000,0000,0000,,gonna say each IP address gets this lower\Nquota Dialogue: 0,0:21:22.83,0:21:24.65,Default,,0000,0000,0000,,of how many login requests they can make. Dialogue: 0,0:21:24.65,0:21:27.19,Default,,0000,0000,0000,,Thinking of this same problem from a, from\Na Dialogue: 0,0:21:27.19,0:21:29.91,Default,,0000,0000,0000,,kind of different angle, you might want to\Nimagine Dialogue: 0,0:21:29.91,0:21:32.25,Default,,0000,0000,0000,,a, a situation where a, an attacker is using Dialogue: 0,0:21:32.25,0:21:35.58,Default,,0000,0000,0000,,many different IP addresses to try to crack\Npasswords Dialogue: 0,0:21:35.58,0:21:39.02,Default,,0000,0000,0000,,for one particular email address, right. Maybe\Nit's the Dialogue: 0,0:21:39.02,0:21:41.71,Default,,0000,0000,0000,,founder's email address or something like\Nthat. Dialogue: 0,0:21:41.71,0:21:44.29,Default,,0000,0000,0000,,So you, so putting on your security hat, you Dialogue: 0,0:21:44.29,0:21:45.63,Default,,0000,0000,0000,,can be like, how am I gonna be safe Dialogue: 0,0:21:45.63,0:21:48.61,Default,,0000,0000,0000,,from those kinds of requests? The only change\Nhere Dialogue: 0,0:21:48.61,0:21:51.66,Default,,0000,0000,0000,,is what we're returning. Instead of the IP\Naddress, Dialogue: 0,0:21:51.66,0:21:54.79,Default,,0000,0000,0000,,we're returning the value of the email parameter.\NSo Dialogue: 0,0:21:54.79,0:21:57.78,Default,,0000,0000,0000,,this is a, a sort of little different way Dialogue: 0,0:21:57.78,0:22:00.89,Default,,0000,0000,0000,,of thinking about throttles, of saying, whoever\Nyou are, Dialogue: 0,0:22:00.89,0:22:02.79,Default,,0000,0000,0000,,if you're trying to login with this one particular Dialogue: 0,0:22:02.79,0:22:05.81,Default,,0000,0000,0000,,IP address, you can only do it five times Dialogue: 0,0:22:05.81,0:22:07.90,Default,,0000,0000,0000,,every twenty seconds. Dialogue: 0,0:22:07.90,0:22:11.37,Default,,0000,0000,0000,,So those are two throttles that pretty much\Neverybody Dialogue: 0,0:22:11.37,0:22:13.61,Default,,0000,0000,0000,,should, should have that feature on their\Nwebsite. If Dialogue: 0,0:22:13.61,0:22:15.96,Default,,0000,0000,0000,,you haven't been bitten by it yet, it's probably Dialogue: 0,0:22:15.96,0:22:19.28,Default,,0000,0000,0000,,just a matter of time. Dialogue: 0,0:22:19.28,0:22:22.36,Default,,0000,0000,0000,,Another pretty cool Rack::Attack feature are\Nblacklists. So these Dialogue: 0,0:22:22.36,0:22:24.06,Default,,0000,0000,0000,,are requests that you don't even want to throttle. Dialogue: 0,0:22:24.06,0:22:27.17,Default,,0000,0000,0000,,Like, you're not gonna allow them at all.\NJust, Dialogue: 0,0:22:27.17,0:22:30.31,Default,,0000,0000,0000,,access denied every time they happen. I kind,\NI Dialogue: 0,0:22:30.31,0:22:33.14,Default,,0000,0000,0000,,was gonna call these blocks, but like blocks,\NI Dialogue: 0,0:22:33.14,0:22:35.02,Default,,0000,0000,0000,,can't call them blocks. Because in Ruby the,\Nlike, Dialogue: 0,0:22:35.02,0:22:37.25,Default,,0000,0000,0000,,that's already a different thing. Dialogue: 0,0:22:37.25,0:22:39.09,Default,,0000,0000,0000,,So hence the term blacklists. Dialogue: 0,0:22:39.09,0:22:42.13,Default,,0000,0000,0000,,Here's an example of a pretty handy blacklist.\NSay Dialogue: 0,0:22:42.13,0:22:44.61,Default,,0000,0000,0000,,you have an admin section of your website,\Nand Dialogue: 0,0:22:44.61,0:22:46.75,Default,,0000,0000,0000,,you want to restrict access to the admin section Dialogue: 0,0:22:46.75,0:22:49.63,Default,,0000,0000,0000,,to just like, your one office IP address.\NSo Dialogue: 0,0:22:49.63,0:22:52.78,Default,,0000,0000,0000,,this is, again, it's using the, it's using\Nthe Dialogue: 0,0:22:52.78,0:22:56.78,Default,,0000,0000,0000,,blacklist class method on Rack::Attack to\Nsort of configure Dialogue: 0,0:22:56.78,0:22:58.57,Default,,0000,0000,0000,,this in the middleware. You would, you would\Nput Dialogue: 0,0:22:58.57,0:23:03.30,Default,,0000,0000,0000,,this in an initializer, saying that, you're\Ngiven a Dialogue: 0,0:23:03.30,0:23:07.01,Default,,0000,0000,0000,,name like bad_admin_ip, and one of the things,\Nlike, Dialogue: 0,0:23:07.01,0:23:08.67,Default,,0000,0000,0000,,it's different than throttles in that we don't\Nhave Dialogue: 0,0:23:08.67,0:23:10.80,Default,,0000,0000,0000,,to pass along a limit of a period, because Dialogue: 0,0:23:10.80,0:23:13.97,Default,,0000,0000,0000,,it just like, it doesn't apply to blacklists. Dialogue: 0,0:23:13.97,0:23:15.72,Default,,0000,0000,0000,,But it has the same logic where if the Dialogue: 0,0:23:15.72,0:23:19.48,Default,,0000,0000,0000,,return value of this block is truthy, we're\Ngonna, Dialogue: 0,0:23:19.48,0:23:22.45,Default,,0000,0000,0000,,like, just give them the very fast access\Ndenied Dialogue: 0,0:23:22.45,0:23:24.40,Default,,0000,0000,0000,,message. If it's false, then we're gonna let\Nthe Dialogue: 0,0:23:24.40,0:23:26.92,Default,,0000,0000,0000,,request through. So this is saying, if you're\Nmaking Dialogue: 0,0:23:26.92,0:23:30.69,Default,,0000,0000,0000,,a request to a url that starts with admin, Dialogue: 0,0:23:30.69,0:23:33.51,Default,,0000,0000,0000,,and you are not from this IP address, we're Dialogue: 0,0:23:33.51,0:23:38.41,Default,,0000,0000,0000,,gonna, we're gonna just give you an access\Ndenied. Dialogue: 0,0:23:38.41,0:23:41.26,Default,,0000,0000,0000,,This is something that KickStarter uses. We\Ncall it Dialogue: 0,0:23:41.26,0:23:46.13,Default,,0000,0000,0000,,the starve the trolls feature. So this is,\Nif, Dialogue: 0,0:23:46.13,0:23:48.63,Default,,0000,0000,0000,,if you're one of our banned IPs that our Dialogue: 0,0:23:48.63,0:23:52.29,Default,,0000,0000,0000,,customer support team decides which IPs get\Nbanned, you Dialogue: 0,0:23:52.29,0:23:54.92,Default,,0000,0000,0000,,cannot make any request that's not a get request. Dialogue: 0,0:23:54.92,0:23:57.52,Default,,0000,0000,0000,,Or, put another way, you can only make get Dialogue: 0,0:23:57.52,0:24:00.37,Default,,0000,0000,0000,,requests if you're from these IP addresses. Dialogue: 0,0:24:00.37,0:24:01.92,Default,,0000,0000,0000,,So let's think about what it's like to use Dialogue: 0,0:24:01.92,0:24:05.46,Default,,0000,0000,0000,,a dynamic web application if you're only using\Ngets. Dialogue: 0,0:24:05.46,0:24:07.73,Default,,0000,0000,0000,,You can't sign up. You can't log in. You Dialogue: 0,0:24:07.73,0:24:11.06,Default,,0000,0000,0000,,can't post comments. These are, these are,\Nwe sort Dialogue: 0,0:24:11.06,0:24:14.64,Default,,0000,0000,0000,,of use this as a measure of last resort Dialogue: 0,0:24:14.64,0:24:18.14,Default,,0000,0000,0000,,for people who are, who are bad actors in Dialogue: 0,0:24:18.14,0:24:20.70,Default,,0000,0000,0000,,our community. Any big community has, you\Nknow, knows Dialogue: 0,0:24:20.70,0:24:22.61,Default,,0000,0000,0000,,that this stuff is sort of inevitable, to\Nhave Dialogue: 0,0:24:22.61,0:24:26.57,Default,,0000,0000,0000,,a few rotten apples. Dialogue: 0,0:24:26.57,0:24:28.59,Default,,0000,0000,0000,,And this has been like really fast and effective Dialogue: 0,0:24:28.59,0:24:30.97,Default,,0000,0000,0000,,for our community team to be able to just Dialogue: 0,0:24:30.97,0:24:34.08,Default,,0000,0000,0000,,like put these IP addresses into a yaml file. Dialogue: 0,0:24:34.08,0:24:36.10,Default,,0000,0000,0000,,They leave them there for about a week or Dialogue: 0,0:24:36.10,0:24:38.84,Default,,0000,0000,0000,,so, and you know gives that person sort of Dialogue: 0,0:24:38.84,0:24:41.17,Default,,0000,0000,0000,,time to cool off, where they're not gonna\Ngo Dialogue: 0,0:24:41.17,0:24:43.49,Default,,0000,0000,0000,,around signing up for a bunch of accounts\Nand, Dialogue: 0,0:24:43.49,0:24:46.79,Default,,0000,0000,0000,,and maybe doing bad stuff or, like, posting\Nmessages Dialogue: 0,0:24:46.79,0:24:49.42,Default,,0000,0000,0000,,or stuff like that. Dialogue: 0,0:24:49.42,0:24:52.19,Default,,0000,0000,0000,,So this is, I don't, I was really, I Dialogue: 0,0:24:52.19,0:24:54.38,Default,,0000,0000,0000,,was sort of struck when we started doing this Dialogue: 0,0:24:54.38,0:24:57.70,Default,,0000,0000,0000,,of like how simple this was in code, and Dialogue: 0,0:24:57.70,0:25:01.42,Default,,0000,0000,0000,,how much it helped our CSS, or, our community Dialogue: 0,0:25:01.42,0:25:04.35,Default,,0000,0000,0000,,support team. So this is another example of,\Nlike, Dialogue: 0,0:25:04.35,0:25:06.25,Default,,0000,0000,0000,,sort of an area where I wouldn't expect Rack::Attack Dialogue: 0,0:25:06.25,0:25:08.15,Default,,0000,0000,0000,,to be very helpful, but it ended up being Dialogue: 0,0:25:08.15,0:25:10.76,Default,,0000,0000,0000,,very helpful. Dialogue: 0,0:25:10.76,0:25:16.88,Default,,0000,0000,0000,,Another Rack::Attack nice to have feature\Nis ActiveSupport::Notifications. So, Dialogue: 0,0:25:16.88,0:25:20.87,Default,,0000,0000,0000,,every time, if, if ActiveSupport::Notifications\Nare in your app, Dialogue: 0,0:25:20.87,0:25:24.36,Default,,0000,0000,0000,,and so for any Rails app they're already there, Dialogue: 0,0:25:24.36,0:25:28.62,Default,,0000,0000,0000,,we will fire a ActiveSupport notification\Nevent every time Dialogue: 0,0:25:28.62,0:25:32.55,Default,,0000,0000,0000,,a request gets blocked or throttled. So this\Nmeans Dialogue: 0,0:25:32.55,0:25:35.47,Default,,0000,0000,0000,,you can have a subscriber to these events\Nthat's Dialogue: 0,0:25:35.47,0:25:38.04,Default,,0000,0000,0000,,gonna log or graph these events and stuff\Nlike Dialogue: 0,0:25:38.04,0:25:40.49,Default,,0000,0000,0000,,that. There are examples of how to do that Dialogue: 0,0:25:40.49,0:25:43.97,Default,,0000,0000,0000,,in the README on GitHub. Dialogue: 0,0:25:43.97,0:25:48.39,Default,,0000,0000,0000,,So thinking of where Rack::Attack might fall\Nin the Dialogue: 0,0:25:48.39,0:25:50.52,Default,,0000,0000,0000,,set of tools you use to keep your site Dialogue: 0,0:25:50.52,0:25:54.21,Default,,0000,0000,0000,,fast and reliable, it is, it's not a silver Dialogue: 0,0:25:54.21,0:25:57.34,Default,,0000,0000,0000,,bullet. Like, it very much compliments things\Nlike, the Dialogue: 0,0:25:57.34,0:26:04.13,Default,,0000,0000,0000,,iptables firewall, or nginx limit_conn_zone,\Nlimit conn module to Dialogue: 0,0:26:04.13,0:26:06.66,Default,,0000,0000,0000,,limit the number of concurrent requests per\NIP address. Dialogue: 0,0:26:06.66,0:26:08.27,Default,,0000,0000,0000,,Or if you have, like, a CDN or a Dialogue: 0,0:26:08.27,0:26:11.33,Default,,0000,0000,0000,,web app firewall. So, like, you know, hardware\Nto, Dialogue: 0,0:26:11.33,0:26:13.98,Default,,0000,0000,0000,,to keep your website fast and reliable. Like,\Nkeep Dialogue: 0,0:26:13.98,0:26:14.95,Default,,0000,0000,0000,,doing those. Dialogue: 0,0:26:14.95,0:26:18.21,Default,,0000,0000,0000,,Rack::Attack's not a silver bullet. You know,\Nit's, if Dialogue: 0,0:26:18.21,0:26:22.94,Default,,0000,0000,0000,,you have a mtp reflection ddos attack, like,\Nit's Dialogue: 0,0:26:22.94,0:26:27.46,Default,,0000,0000,0000,,gonna overwhelm your Unicorn or Heroku processes\Npretty fast. Dialogue: 0,0:26:27.46,0:26:30.67,Default,,0000,0000,0000,,You need something else. But, what Rack::Attack\Nreally is Dialogue: 0,0:26:30.67,0:26:34.41,Default,,0000,0000,0000,,good at is, it's Ruby. It knows everything\Nabout Dialogue: 0,0:26:34.41,0:26:36.47,Default,,0000,0000,0000,,your app, like, I mean, because it's in your Dialogue: 0,0:26:36.47,0:26:41.08,Default,,0000,0000,0000,,application, you can use other logic from\Nyour app. Dialogue: 0,0:26:41.08,0:26:43.35,Default,,0000,0000,0000,,Because it's Ruby, it's easy to test. You\Nwrite Dialogue: 0,0:26:43.35,0:26:45.73,Default,,0000,0000,0000,,integration tests for it the same way you\Nwrite Dialogue: 0,0:26:45.73,0:26:48.00,Default,,0000,0000,0000,,tests for the rest of your application. Dialogue: 0,0:26:48.00,0:26:49.60,Default,,0000,0000,0000,,And it's easy to deploy, because it's Ruby\Ncode. Dialogue: 0,0:26:49.60,0:26:51.94,Default,,0000,0000,0000,,I don't know how you deploy changes to a Dialogue: 0,0:26:51.94,0:26:54.60,Default,,0000,0000,0000,,CDN or a web app firewall, but it's probably Dialogue: 0,0:26:54.60,0:26:57.57,Default,,0000,0000,0000,,a different process than how you deploy your\NRuby Dialogue: 0,0:26:57.57,0:27:01.47,Default,,0000,0000,0000,,code. And, and this is something that a lot, Dialogue: 0,0:27:01.47,0:27:05.74,Default,,0000,0000,0000,,everybody on our engineering team is comfortable\Ndoing. Dialogue: 0,0:27:05.74,0:27:08.66,Default,,0000,0000,0000,,So that, that's why, that's where Rack::Attack\Ncan fit Dialogue: 0,0:27:08.66,0:27:13.73,Default,,0000,0000,0000,,in into your application security mindset. Dialogue: 0,0:27:13.73,0:27:16.01,Default,,0000,0000,0000,,I also wanted to call out and say thank Dialogue: 0,0:27:16.01,0:27:19.56,Default,,0000,0000,0000,,you to my many GitHub contributors. These\Npeople are Dialogue: 0,0:27:19.56,0:27:23.54,Default,,0000,0000,0000,,really awesome and they've taken Rack::Att-\Nlike, added really Dialogue: 0,0:27:23.54,0:27:26.20,Default,,0000,0000,0000,,cool features, like allow to ban and fail\Nto Dialogue: 0,0:27:26.20,0:27:29.30,Default,,0000,0000,0000,,ban, and they've cleaned up documentation\Nand they've made Dialogue: 0,0:27:29.30,0:27:32.21,Default,,0000,0000,0000,,the tests a lot better. They support, added\Nreddis Dialogue: 0,0:27:32.21,0:27:37.00,Default,,0000,0000,0000,,support was, it used to be just memcache.\NBut Dialogue: 0,0:27:37.00,0:27:40.75,Default,,0000,0000,0000,,these people are doing fantastic things with\Nopen source. Dialogue: 0,0:27:40.75,0:27:44.18,Default,,0000,0000,0000,,They're from five different continents, too,\Nwhich, like it Dialogue: 0,0:27:44.18,0:27:46.53,Default,,0000,0000,0000,,feels so cool to put code out there and, Dialogue: 0,0:27:46.53,0:27:49.73,Default,,0000,0000,0000,,like, people from five different continents\Ncontribute to it Dialogue: 0,0:27:49.73,0:27:51.82,Default,,0000,0000,0000,,because they find it useful. Dialogue: 0,0:27:51.82,0:27:56.19,Default,,0000,0000,0000,,So, more like that please. Dialogue: 0,0:27:56.19,0:28:02.50,Default,,0000,0000,0000,,So, sort of wrapping up, the web, weird stuff Dialogue: 0,0:28:02.50,0:28:06.70,Default,,0000,0000,0000,,happens on the web. It's inevitable. It's\Ngood in Dialogue: 0,0:28:06.70,0:28:08.60,Default,,0000,0000,0000,,a lot of cases. I, I like that, you Dialogue: 0,0:28:08.60,0:28:11.58,Default,,0000,0000,0000,,know, people write really innovative things\Nand, and stuff Dialogue: 0,0:28:11.58,0:28:13.05,Default,,0000,0000,0000,,that I would never would have come up with. Dialogue: 0,0:28:13.05,0:28:15.52,Default,,0000,0000,0000,,Like, that's fantastic. So I hope the web\Nstays Dialogue: 0,0:28:15.52,0:28:17.96,Default,,0000,0000,0000,,weird. But I also hope that the website stays Dialogue: 0,0:28:17.96,0:28:21.02,Default,,0000,0000,0000,,up. And Rack::Attack lets you have the best\Nof Dialogue: 0,0:28:21.02,0:28:24.47,Default,,0000,0000,0000,,both worlds. Dialogue: 0,0:28:24.47,0:28:27.84,Default,,0000,0000,0000,,So that's all I had. That's, that's Rack::Attack\Nat Dialogue: 0,0:28:27.84,0:28:31.40,Default,,0000,0000,0000,,KickStarter. If you have any quest- I'd love\Nto Dialogue: 0,0:28:31.40,0:28:34.52,Default,,0000,0000,0000,,answer any questions if people have them.\NAnd, if Dialogue: 0,0:28:34.52,0:28:36.46,Default,,0000,0000,0000,,you're more comfortable, hit me up on Twitter\Nor Dialogue: 0,0:28:36.46,0:28:38.74,Default,,0000,0000,0000,,find me after the talk.