Join Evan Johnson as he speaks with security professionals about recent security news!
Whoops, I was muted. Here we go. Welcome to Hacker Time. I'm your host, Evan Johnson, coming from Cloudflare's security team.
And we have a very exciting episode today.
We're going to do some live programming and keep doing what we've been doing, building security tools with Cloudflare Workers.
You'll notice I've got my Black History Month background going.
I think it's a great month to get outside your comfort zone, no matter who you are, and learn about people, other cultures that you're maybe less familiar with, and learn about history that you might be less familiar with, no matter who you are, and some housekeeping about the show.
This week, we're doing live programming, and next week, I'm really excited that we're going to have Dr.
David Brumley from Carnegie Mellon and the CEO of For All Secure on Hacker Time as our guest.
He's somebody who I really look up to in the field, and he is a really respected computer scientist.
So I'm really glad that he's joining us. He's our first guest on Hacker Time with a Wikipedia page.
So that's how you know that Hacker Time is the number one security show out there.
I'm telling you all, number one security show out there doing it.
And all right, well, let's dive into live programming because it always seems to go so fast.
And this is where I'm doing my work, github.com slash ejcx slash cftv.
All the work that I've been doing up to now is checked into this repo, and I'm going to be blasting things away in here.
I'm going to be writing code and deleting code, and so you'll have to go back in time to really dig out some of the code that I wrote through git history.
And this week, I thought we could add some dependencies, but also try to build a user login flow.
I think the user login flow is a great place to learn about security fundamentals, and I think what you'll see in the long term is, people are going to want to use Cloudflare Workers for authentication and authorization, because the architecture and the way Cloudflare Workers works, it's really good for being your authentication gateway, for your authorization gateway enforcing access control.
And Cloudflare has a bunch of products that does this, but I think a lot of people will benefit from building custom, their own custom needs on it as well, because everybody can release a access control product, and then every company is just a little bit different and has their own flair of exactly what they need.
And workers is general enough that you can do that and accomplish what you need.
Okay, so without further ado, we're going to be using dependencies working in this repo, and I've already got it set up.
I've already got some of it set up. I've got my hello world here.
So we're starting with hello world, and we're going to be doing some work in here.
I just got my GitHub SSH key set up. You can look at that, my public key art up there.
Okay, so let's start.
I've only got my worker router set up, hello, and this fetch thing.
So let us start from there, and we need a form. We need a place to submit a username and password.
So we previously had this. We had a form. Oh, no.
It's not all. I might have blown away some helpful stuff.
That's okay, though. Some of the work that we did last week might have been lost because I didn't check it in, but that's okay.
We'll start with this form. Sometimes the best code is the code that you no longer have.
So we need to start here. Just a simple form and a body and a closed brace. Sorry, somebody called me out last week because I didn't have a closed curly brace or a closed HTML tag on my HTML.
So I apologize. I apologize for that. That would be better.
We don't actually need an action.
We don't actually need this. Let's just start with a label that says username.
ID that says username. Name is username. We don't need any of these breaks.
And then we can do another for password. And it's very important to change your type to password.
I guess maybe it's not very important, but it is a controversial topic in the security world.
Is there really any benefit to obscuring the password field?
If you're ever with a bunch of security people and need a conversation starter, that one is a good one.
Just make sure if you're looking for something controversial.
Here we go.
Wrangler publish. This should get us our form.
Actually, this won't get us our form. It'll get close, though.
Yeah, we need to set our headers. Let's try to do that on the fly here.
You know, I just really don't remember.
Let's look in git history. Player, worker, header.
Where I'd like to get to today is I'd like to accept a password and store it hashed securely and be able to fully log in.
That might be a tall ask, though.
We'll see. We'll see how it goes. Cloudflare Workers, response headers.
I believe it's like new headers.
Yeah, let's try that. And then you include it in this object.
Also in the response.
Let's just try this.
Age equals new headers.
And it's something like content type. HTML, something like this.
There's like a 50-50 shot of this working. Let's give it a try. Let's give it a try.
Close your quotes.
Of course. And voila, it's working.
Okay, it's not pretty, though. It is not pretty at all. Let's clean this up just a little.
Sometimes I like to put the input inside the label.
I think that'll change some of the CSS.
How this renders ever so slightly. And it still says use URL here instead of username.
Let's try that again. Change that, too.
Did not change it one bit.
I'll just add a break here. I did need those breaks that I removed.
Okay, this looks a little better.
I'll add one more. Let's try to get the casing consistent.
This looks good.
I'm going to steal the same CSS I stole last time from my personal website.
Because I just think it makes things with very little content look a little better.
In a very simple way.
It's in the static. Where is it?
Util. That's where it is. Just this whole style block will go a long way.
Got the casing properly set.
I need another break here. And should work. Should be better.
Should be a lot better. Oh, yeah, look at that.
That's much nicer. Password field all obscured as expected. Okay.
This, you can't beat this. I'm going to change this to slash. And.
All right, so we can actually like put in a username like. And submit and nothing will happen.
I just submitted it in the URL field. This is a good thing to know in the security.
When you're looking at the security of an application, getting a password in the get parameters is something that is really annoying.
If you're on a defending team.
Because this means that it'll get logged and logged somewhere because it's in the URL parameters.
And. That's not a good thing to submit your password.
In plain text. Like this. In the get parameters because it also gets stored in logs in the back end and it also gets stored in users browsers.
And you don't have a default action on the form for post.
Since there is no post here. It's submitting it as get.
If I set the default form action to post you wouldn't see this, but since, since there is no default action here of submitting via post you're seeing it in and get so always make sure you have default action on your form to be post.
Okay, so now we got to do the hard work. We need a place to receive the form submission.
Let's start with a post account.
Um, and then in the form we need to submit to create account, or I think it's action.
And the method equals post.
You know I'm no, I'm no HTML person, because I just haven't done it enough recently, but we can give it a try.
Oh boy, where's network here it is.
All right. This is way too large. Possible to see.
All right. EJC x a let's see if it submits it as a post.
Perfect. It did. Yep, that's what we want to see username EJC x password, a and it submitted a post to the right endpoint, we're in business.
Okay. Let's, let's do this. You'll see our worker through an exception that's because we didn't return a response here, and our worker so we need to return a response.
What should we do.
For now, we'll just return a blank one. Okay.
Which is these. That's cool. These are cool. Okay, so we need to receive this password and username stored in workers KV securely, and then allow and then tell people when they have logged in successfully or not.
So, what's the best way to do that.
First, we need to parse the post parameters. Workers parse post parameters.
Read post. It's so easy. There is so much helpful documentation on our workers docs it amazes me how much I'm able to copy and paste and cobble stuff together that works.
It is fantastic. All right, but how do you parse read post read request body.
This is looking promising.
Form data. Here we go. And. All right, but this works first try. So no AI, no auto indentation in them.
Must have when you're copying and pasting a lot. So we are going to parse the form data put it in form data and then what is this body going to do here.
Body. It seems to be transposing things from form data into a I'm going to guess form data is just an array of things so it'll say username.
It's an array and then the zeroth element will be.
Is that the oh yes yes what's happening here is there's a bunch of this body thing doesn't seem like I need this body thing at all.
So I'll just parse the form data and let me return it.
Return new response JSON stringify form data. And now when we submit this should get a nice response.
Nothing. Very suspect.
Why is that the case we submitted the right data. Why could that be.
Maybe I do need that extra bit of code. Let's just, let's trust the docs.
The docs are always right. When you think you know more than the docs you know you've made a problem.
You're either next level where you really do know more than the docs or, but usually not.
Especially if you're copying and pasting code regularly from the docs.
It's usually best to trust, trust them.
Huh, what did I break here. Oh, this needs to be a return.
Once this works, I'm going to get a package for hashing the password and we're going to talk about password hashing and storage quickly.
Worker through stringify body. Why doesn't this work. Request form data body. Entry const entry of form data entries.
Is there anything special I need to do in the form data here.
If content type includes form.
No, this looks almost exactly like what I'm doing.
But I've done something wrong. I'm sure it.
Form data, a weight. Let me just start fresh here.
Okay. Ah, okay, something was a little. Yeah, they. Thanks Chrome Chrome knows that my password is no good here.
Okay, so this works just fine just something was updating and was a little slow.
This is perfect. We've got it working we've got our entries we've got two tuples of username and password in here.
And we'll just do one error check if. If. If body. Username, if not body that username.
Body dot password.
If we can't find the password and we can't find the username, or we can't find the username.
If either one of those is not set, then we would like to return a new response to redirect you to response dot redirect.
Yes, I don't know if you need new response.
I don't think you do. I think this will just return a response object.
Let's give it one try though. Okay. Turn up their worker.
Direct. Return response destination and status code so this is going to be a 301.
Okay. And with that we've done our, we've done our due diligence validating this and let's get to the most important part.
We got to store this username and password hash.
So, what's the best way to do that. I will tell you that a simple and secure, there's, there's many different functions that you can use for hashing a password.
People have written great articles about the best way to do it.
There are a few algorithms that most people recommend.
I'm going to start by saying you don't want to use MD five or shot two five six.
The properties of a good password hashing function are that first of all it's kind of slow.
You don't want something that somebody with a like specialized specialized hashing brute forcing machine can generate a lot of hashes for.
So you want something that's kind of slow and intense to calculate.
And so that's the first property you want and then the second is all of the cryptographic strength from most that that some of those algorithms have like you want collision resistance.
All of the strong, all of the strong cryptographic properties from a strong cryptographic hash added to slowness.
So, one, people recommend bcrypt, people recommend scrypt.
There's some other fancy ones like argon. And for simplicity, we're going to use bcrypt today, because I'm sure we can find an MPM module.
Now I have not verified the security of this module myself, but it does have a lot of downloads.
And that is one thing to consider the usage of it. How widely use it is.
And since this is a toy example, I'm not going to think twice. But if you're using this in production.
First of all, don't use my code in production. Second of all, if you're going to use node bcrypt JS in production.
Give it at least a give it a thought before you Do your due diligence.
Alright, so I included this.
Let's give it a try. Async recommended.
Okay, let's try to generate a salt.
A lot of callbacks here.
It's kind of annoying. But that should be okay.
Let's just give it a try.
Let's just try it really quick. Let hash Password hash equals await this thing.
I honestly don't know if this is allowed or not.
I feel like it's not, though. Wrangler publish It would be a miracle if this works on the first try.
I give it a 30% chance and we only have a few minutes left.
So it's unfortunate. We might not finish this get to where I wanted to I just do too much talking, you know.
Whoa, what did I do Okay, it did not like this be crypt.
It did not like our Be crypt library we used.
Let me check if there's one other Oh, I like this zero dependencies be crypt JS.
It actually looks like there's more More usage of this, which is good bar be crypt Password So we first need a salt.
Same kind of logic here where you probably want to you probably want to Verify this type of function yourself.
If you're going to or this this type of library yourself do some of your own due diligence.
Before using it in production.
But I would I give us a better chance. I gave us 30% on that last one.
I give us 42% here. Oh, NPM install be crypt. Yes. And then I'm going to do some surgery here RM RF node modules.
We are building we are publishing As the package gets bigger, it takes a little more time to run regular publish because it's got to grab all the extra stuff.
Whoo. Okay. We actually have the password here.
I'm amped so 42% more like 100% This is a be crypt hash and you know that because of these.
It's really easy to tell when you look at a be crypt hash because you see this dollar sign something dollar sign something dollar sign something And And this is a format with the type of hash.
It is the type of complexity and the number of rounds that you've put into here.
If we change the salt rounds to 12 this will probably change to 12 and then the actual The actual data here, which we can type into x x D.
And you can see this is 16 or is this 322468 10 1214 16 yeah 16 bytes here.
Another 16 another 16. This is actually the hash and the salt combined And we are unfortunately out of time.
So we'll make sure we finish this up after we have Dr.
David Brumley on next week. I'm so excited. Thanks for joining me and we'll we'll hash these passwords together and securely do this next week.