WEBVTT

00:00.380 --> 00:00.980
Okay guys.

00:00.980 --> 00:05.300
So in the first part we started validating the token.

00:05.330 --> 00:10.910
The current problem is that the CSRF token doesn't exist anywhere yet.

00:10.910 --> 00:19.460
That's why we need to jump to the CSRF function and generate it first before we attempt to validate

00:19.460 --> 00:19.970
it.

00:19.970 --> 00:25.790
By the way, I think we should stick to adding the strict types everywhere.

00:25.790 --> 00:27.500
Let me start with this.

00:28.730 --> 00:29.300
All right.

00:29.330 --> 00:34.100
Next up let's add a function that can generate the token.

00:35.930 --> 00:41.360
I can call this generate CSRF token.

00:41.840 --> 00:45.380
No arguments here and it returns a string.

00:45.410 --> 00:52.070
Now the CSRF token needs to be random and it needs to be automatically generated.

00:52.070 --> 00:55.820
And it needs to be also kind of unique.

00:56.060 --> 01:05.730
I would also like to add a constant, which would be a setting, And this would be the token length.

01:05.940 --> 01:09.930
So just how many characters there are in a token?

01:09.930 --> 01:15.240
And another setting I'd like is the token expiry time.

01:17.370 --> 01:21.090
Let's call it lifetime and this is in seconds.

01:21.300 --> 01:26.040
So let's multiply by maybe 30.

01:26.070 --> 01:29.490
This is 30 minutes.

01:30.300 --> 01:30.630
Okay.

01:30.660 --> 01:38.190
Going back to the generation token is essentially some random bytes.

01:38.190 --> 01:48.330
So let's generate the random bytes using this PHP function and the length of the random string.

01:48.330 --> 01:50.100
We've got a constant for that.

01:50.100 --> 01:53.550
So this is CSRF token length.

01:55.980 --> 02:00.600
So from this function let's return this token.

02:00.600 --> 02:03.390
And I'd like to test this function.

02:03.390 --> 02:04.910
Test it manually.

02:04.940 --> 02:07.430
That's why I'm just going to call it.

02:07.460 --> 02:09.050
Inside this file.

02:09.050 --> 02:14.270
So we just make sure it is called on every single page and we stop the execution.

02:16.370 --> 02:16.850
Okay.

02:16.850 --> 02:18.620
So I can just refresh the page.

02:18.620 --> 02:20.000
And this is how it looks like.

02:20.030 --> 02:25.040
As you see, it's not really characters that make a lot of sense.

02:25.040 --> 02:34.250
And to convert this binary characters which just contain some bytes that just don't have a corresponding

02:34.250 --> 02:35.300
character.

02:35.300 --> 02:44.270
So to make it look like an actual string, we're going to use another function called bean to hex.

02:44.300 --> 02:52.130
It just converts the binary data which we've just generated to hexadecimal representation.

02:52.880 --> 02:56.870
Now this is how our token would look like.

02:59.480 --> 03:02.870
So this is still safe and still unique.

03:02.900 --> 03:08.010
As you can see, when I'm refreshing it is different every single time.

03:08.040 --> 03:15.270
There is really a low chance that we're gonna generate the same token for your user, and the malicious

03:15.270 --> 03:19.290
user that tries to send the form in his name.

03:19.560 --> 03:22.710
There's almost zero chance this will happen.

03:22.740 --> 03:31.050
That's why now we should store this in the session, which we do by setting it on the super global.

03:31.710 --> 03:38.880
So we've got the CSRF token itself and that's just the token we've generated.

03:38.940 --> 03:42.480
And another thing we need is the token time.

03:42.480 --> 03:47.940
So basically when was this token generated.

03:47.970 --> 03:52.590
This is the token time for that.

03:52.620 --> 04:00.900
We're just going to use the PHP time function that will generate the current Unix timestamp, which

04:00.900 --> 04:06.750
is the seconds that have passed since the so-called Unix epoch.

04:10.160 --> 04:13.670
So this function generates a new token.

04:13.670 --> 04:20.180
I think we need another function for this CSRF functionality to be really useful.

04:20.180 --> 04:23.420
That will just return the current token.

04:23.450 --> 04:30.950
This would be called get current CSRF token doesn't have any parameters and returns a string.

04:30.950 --> 04:46.310
Now the job of this function is to check if there is a valid Non-expired token already and return if

04:47.390 --> 04:55.550
it exists, but if it doesn't exist, if there is no current token or the token is just invalid, we

04:55.550 --> 05:02.270
need to generate a new one and return it.

05:04.190 --> 05:12.150
So the job of this function is to take all the mental overhead of implementing CSRF tokens in forms

05:12.180 --> 05:19.620
from the mind of a future implementer, someone who would have to use this functionality.

05:19.650 --> 05:27.930
Whether this is ourselves or some other developer, all you need to do is first make sure you call this

05:27.930 --> 05:37.830
function within a form markup, and then on the root handler that handles the submission of the form,

05:37.830 --> 05:39.720
you validate the token.

05:39.720 --> 05:43.140
So there are only two steps you need to think about.

05:43.170 --> 05:45.660
Now let's implement this function.

05:47.820 --> 05:56.280
So let's start with an if statement that will check if we already have the token and token time inside

05:56.280 --> 06:01.890
the session, because if we don't then we're just going to regenerate it.

06:02.070 --> 06:11.300
So we use Eset to check if two values exist inside the session the see us arrive?

06:11.330 --> 06:12.320
Token.

06:14.510 --> 06:18.230
And the other one is the CSRF token time.

06:18.230 --> 06:25.130
They are both crucial and they both need to be set on the session token time.

06:25.220 --> 06:30.770
So this is the first condition that would trigger the token regeneration.

06:30.770 --> 06:36.320
And in this case we can just return generate CSRF token.

06:37.550 --> 06:46.430
We are just generating it if it doesn't exist now if it does exist we return it straight from the session.

06:46.910 --> 06:53.660
So we just get session CSRF token.

06:55.550 --> 06:57.260
Now there is another condition here.

06:57.260 --> 07:04.370
So if it doesn't exist or it is expired we also need to regenerate it.

07:05.270 --> 07:13.680
So this other condition is calling the time function and subtracting Attracting the token generation

07:13.680 --> 07:14.460
time.

07:14.580 --> 07:21.000
So this would be the session CSRF token time.

07:26.250 --> 07:37.800
And if the result of that is more than the CSRF token lifetime, why do we don't have this.

07:37.830 --> 07:41.910
All right so I've misspelled the constant name.

07:41.910 --> 07:45.810
This should be CSRF token lifetime.

07:45.810 --> 07:54.900
So again if the current time minus the time when the token was generated is more than the expected lifetime,

07:54.960 --> 07:57.570
we need to regenerate the token.

07:57.900 --> 08:05.460
Now it seems that we are using this session super global directly a lot of times, and we are typing

08:05.460 --> 08:06.420
this as a key.

08:06.420 --> 08:09.060
So CSRF token token time.

08:09.060 --> 08:13.900
It's easy to make mistakes here to misspell the name and then.

08:13.900 --> 08:16.390
Well, this can be pretty dangerous.

08:16.390 --> 08:22.330
If we just misspell one of those names, it might break the whole functionality.

08:22.360 --> 08:29.650
That's why I'd like us to add additional functions that will be responsible for returning the current

08:29.680 --> 08:38.200
token and time, and also setting the current token and time, because those are always connected.

08:38.230 --> 08:45.880
So let's add a function that will be called get CSRF token and time.

08:48.430 --> 08:54.190
This will always return an array and it just returns right away.

08:54.190 --> 08:56.080
It would be super simple.

08:56.080 --> 09:06.430
It will just contain the entries of the session, which is the CSRF token or null.

09:08.050 --> 09:14.970
And the other element is the CSRF token time or null.

09:15.000 --> 09:23.610
Now, we never have a case where you're gonna be setting the current token and not setting the time.

09:23.640 --> 09:31.770
That's why we also need to set CSRF token and time.

09:33.330 --> 09:38.940
We should always pass a valid token and time does an integer.

09:39.180 --> 09:42.210
This is void, doesn't return anything.

09:42.540 --> 09:44.160
And.

09:47.040 --> 09:49.860
We should be using this code.

09:52.950 --> 09:55.800
And I think we don't actually need the time.

09:55.800 --> 09:57.360
We can just generate it.

09:57.390 --> 10:06.240
Now here let's call set current token and time passing the token.

10:09.540 --> 10:14.190
Now in this place we should be fetching the token.

10:14.190 --> 10:17.800
Now inside this function get current CSRF token.

10:17.800 --> 10:26.020
We're going to use an array destructuring, getting token and time, and the function is called get

10:26.020 --> 10:29.410
CSRF token and time.

10:29.410 --> 10:33.310
So now we have it much simpler.

10:33.430 --> 10:41.410
We can check for the token and time because it would be null if we don't have it inside the session.

10:41.410 --> 10:51.520
And additionally we can even add one another function so we can write a function called is token expired.

10:52.990 --> 11:00.850
It would return boolean and we might pass the token time here, which can be nullable.

11:03.460 --> 11:15.070
And we just return whether time is exactly null or the current time minus the time from the argument

11:15.070 --> 11:20.610
is more than the CSRF token lifetime.

11:20.700 --> 11:22.680
The token is expired.

11:22.710 --> 11:26.580
Now we can simplify this function even more.

11:28.020 --> 11:37.080
We regenerate the token if we don't have the token or time in the session, or if the token is expired,

11:37.710 --> 11:39.420
for which we pass the time.

11:40.770 --> 11:45.570
So it's time to start using the token inside the form.

11:46.260 --> 11:50.520
First, let's jump to the contact get root.

11:50.550 --> 11:54.960
That's the place where we are going to get the current CSRF token.

11:54.960 --> 11:58.950
Just the token, because that's the only thing that we need for the form.

11:58.950 --> 12:03.090
So we're going to be passing some data to this form template.

12:03.270 --> 12:06.150
This can be called CSRF token.

12:06.150 --> 12:11.400
And we can call get current CSRF token.

12:12.360 --> 12:13.410
We are done here.

12:13.440 --> 12:16.260
Now let's jump to the template.

12:16.260 --> 12:25.780
And this is our placeholder for the token, so the token is directly connected to a single form submission.

12:25.810 --> 12:29.590
Every single form should have its own token.

12:29.590 --> 12:34.870
It's not really possible to have 2 or 3 form submissions at the same time.

12:34.870 --> 12:42.550
You can only submit one, so if there is a token generated, we just need to make sure we validate it.

12:42.550 --> 12:51.250
And to have the token sent together with a form, we can add another input of type hidden.

12:51.280 --> 12:56.410
This won't be visible, but the data would be sent together with a form.

12:56.410 --> 13:04.960
It will be called CSRF token and the value will just come from our data.

13:04.960 --> 13:12.250
So this is we echo the data CSRF token.

13:12.250 --> 13:17.050
That's the value we have just passed from the root handler.

13:17.050 --> 13:22.560
And the only thing left is to verify this token.

13:22.560 --> 13:28.410
When this is submitted to the specific route handler, which we already do, we just don't have this

13:28.410 --> 13:30.780
verifying function implemented.

13:32.670 --> 13:39.240
Now, after we save the changes, let me refresh the form and open the DevTools.

13:39.240 --> 13:43.050
I'd like to locate this hidden input.

13:43.800 --> 13:46.620
So let me zoom in here.

13:48.570 --> 13:51.300
I think you can see the form.

13:51.300 --> 13:54.000
And here we've got some inputs and labels.

13:54.000 --> 13:54.870
And there it is.

13:54.870 --> 14:02.160
This is our hidden input with the CSRF token name and the value that was generated and will be valid

14:02.160 --> 14:07.950
for the next 30 minutes unless it expires or you submit the form.

14:07.950 --> 14:13.470
And in that case we're going to be generating a new token for the next submission.

14:13.860 --> 14:16.830
Now, I think we can conclude at this point.

14:16.830 --> 14:22.980
And in the final third video we are going to implement the token verification.
