WEBVTT

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

00:01.010 --> 00:07.970
So next up our next topic is adding the CSRF tokens into our app.

00:08.000 --> 00:12.260
Well fortunately we have already implemented that in the previous project.

00:12.260 --> 00:15.470
But then we were just using functions.

00:15.470 --> 00:19.190
But what we can use is well the logic.

00:19.190 --> 00:23.720
We don't really have to rethink it from scratch.

00:23.720 --> 00:25.610
We don't have to invent anything.

00:25.610 --> 00:29.720
We already know more or less how this should be implemented.

00:29.720 --> 00:38.330
So consider this an exercise in which we are going to convert this code into an object oriented code.

00:38.480 --> 00:47.390
And then we will also create a handy helper function to make it super easy to add those tokens to forms

00:47.390 --> 00:48.590
and verify them.

00:48.590 --> 00:49.670
Let's get started.

00:51.080 --> 00:55.850
All right guys, let's create a service for this CSRF tokens.

00:55.880 --> 00:59.690
Later on we might rethink our namespaces.

00:59.690 --> 01:02.150
Not everything has to be called a service.

01:02.150 --> 01:04.430
For now, let's just keep it this way.

01:05.240 --> 01:09.740
That's our CSF php class.

01:10.700 --> 01:22.220
We are adding a tag, a namespace that's app Services and that's a CSF class.

01:22.220 --> 01:28.910
We might do it all uppercase, but maybe let's just leave it like this.

01:28.940 --> 01:29.420
Okay.

01:29.450 --> 01:32.900
So what things we might copy right away.

01:33.680 --> 01:37.490
Let me define the constants we default to private.

01:37.490 --> 01:44.990
I think it's a sensible idea to always default to private unless you need some changes later on.

01:44.990 --> 01:48.740
Then you can change the visibility of your fields and methods.

01:49.310 --> 01:52.820
And this would be the token length.

01:53.300 --> 01:54.680
Let me just copy that.

01:56.030 --> 01:59.930
The next one is the token lifetime.

02:00.380 --> 02:02.690
This needs to be in seconds.

02:02.690 --> 02:04.780
So I do private const.

02:04.810 --> 02:06.340
That's also an int.

02:08.380 --> 02:12.340
And since we are using a class I don't need this CSRF prefix.

02:12.340 --> 02:14.080
It's obvious what I mean.

02:14.080 --> 02:17.800
What else could I mean inside a CSRF class.

02:18.580 --> 02:23.890
So in this case my PHP is complaining about this constant definition.

02:23.890 --> 02:25.990
Well, the reason is simple.

02:26.020 --> 02:27.340
Let me jump to terminal.

02:27.370 --> 02:29.440
I'm going to show you my PHP version.

02:29.440 --> 02:33.760
So I just have PHP 8.2.4.

02:33.790 --> 02:39.400
It's an older one and I think I have it installed together with Samp.

02:39.460 --> 02:44.110
When I presented how to install Samp for the other course.

02:44.110 --> 02:46.390
Well, that's not the most recent one.

02:46.390 --> 02:55.450
And in the PHP 8.3 or since PHP 8.3, you can add types to constants.

02:55.450 --> 02:59.710
So that's the reason it is highlighting that in red.

02:59.710 --> 03:07.410
So it just depends what PHP version do you have if you have 8.3 or newer, you can add those types.

03:07.410 --> 03:12.450
I'm going to remove them now because for some reason I have an old version.

03:12.450 --> 03:15.540
Anyway, let's continue with the logic.

03:16.320 --> 03:24.360
Next up we should generate a token so we are fresh with token generation because this is what we did

03:24.360 --> 03:26.790
in the Remember Me functionality.

03:26.790 --> 03:29.550
And we're gonna generate the token the same way.

03:29.640 --> 03:35.610
It might be also a good idea in the future to move the token generation to one place so we can generate

03:35.670 --> 03:41.520
tokens in like one class without repeating the logic.

03:41.640 --> 03:45.240
Let's call it generate token without parameters.

03:45.240 --> 03:46.680
It returns a string.

03:46.680 --> 03:50.250
So it's similar to this function.

03:50.250 --> 04:00.210
As you see, we can easily generate a token using this constant that we're going to get from class using

04:00.240 --> 04:02.490
token length.

04:02.490 --> 04:10.020
Everything gets simpler with classes as here in the functions, we need to be very explicit what we

04:10.020 --> 04:13.320
are doing and in the methods.

04:13.320 --> 04:19.470
Well, it's part of a CSV class, so the names can really get to the point.

04:19.470 --> 04:22.050
Like this method name generate token.

04:22.050 --> 04:25.110
It's obvious it is a CSRF token.

04:26.970 --> 04:31.680
Next up, the generation should also add it to the session.

04:31.680 --> 04:35.310
Let's use the super global.

04:36.480 --> 04:41.820
So the session um, I think we can just store an array as well.

04:42.390 --> 04:43.290
So let's do it.

04:43.290 --> 04:46.860
Let's just add a session CSRF token variable.

04:46.860 --> 04:53.430
That's going to be an array here we're going to have a token that's this one.

04:53.490 --> 04:58.560
And it needs an expiry date for that.

04:58.560 --> 05:01.350
We're just going to get the current time.

05:02.550 --> 05:09.420
Plus we need a token expiration time, which we have right here in seconds.

05:09.420 --> 05:11.340
That's our token lifetime.

05:11.340 --> 05:16.080
And we return a string from this method.

05:17.340 --> 05:20.010
And well I'm using self.

05:20.010 --> 05:21.480
It's better to use static.

05:21.480 --> 05:27.150
If it is overridden in the parent class it will get the correct value.

05:27.630 --> 05:30.900
Okay, I'm not sure why I had this semicolon in here.

05:30.900 --> 05:32.460
So this one is fine.

05:32.460 --> 05:37.050
Next up we need another static one called.

05:39.900 --> 05:42.840
To fix this keyword that's function.

05:42.840 --> 05:45.120
And this will be called get token.

05:45.120 --> 05:49.530
So it will give you the current active token.

05:50.760 --> 05:56.010
So um do we have a function like this.

05:58.350 --> 06:00.990
So this would be this one.

06:02.490 --> 06:07.080
We get the current token only if it if it's not expired.

06:07.080 --> 06:10.010
Otherwise we need to just regenerate it.

06:10.040 --> 06:18.560
So we're going to check if maybe we don't have a token already inside the session.

06:18.560 --> 06:21.740
So this is CSRF token.

06:21.890 --> 06:24.830
So that's one reason to regenerate the token.

06:24.830 --> 06:29.990
The other one is to check if it is expired.

06:31.220 --> 06:38.120
So we can have another method called is token expired where we don't need to pass the token because

06:38.120 --> 06:40.760
we always get it from the session.

06:40.760 --> 06:48.440
That's really nice about sessions that they are per user, so you don't need to worry about passing

06:48.440 --> 06:50.030
the values around.

06:50.150 --> 07:00.500
And in this case we're gonna generate a new token and we're going to return it which also stores the

07:00.500 --> 07:03.620
token inside the session.

07:04.130 --> 07:05.270
Like this.

07:05.270 --> 07:10.870
And if we already have a token that is still valid.

07:11.710 --> 07:18.400
We're just going to get it from this session variable, which as we already know, can be an array.

07:18.430 --> 07:22.030
So we use this multi-dimensional array.

07:22.030 --> 07:25.480
So this method does not exist.

07:25.510 --> 07:27.250
It's time to add it.

07:27.280 --> 07:30.370
I think it should be private.

07:30.610 --> 07:32.140
So it's private.

07:32.140 --> 07:38.590
Static function is token expired and it returns a boolean.

07:41.230 --> 07:44.410
And we have a function like this.

07:47.980 --> 07:48.340
Okay.

07:48.340 --> 07:52.150
So let's uh see how this is implemented.

07:52.150 --> 07:55.840
So we also optionally pass the time.

07:55.840 --> 07:59.800
I'm not sure I don't remember what was the reason for it.

07:59.800 --> 08:11.680
Anyway, let me first get the expiry date because it is actually deeply nested inside the session.

08:11.920 --> 08:18.370
Inside CSRF token key expires.

08:20.410 --> 08:22.750
If I'm correct, that's the key name.

08:22.750 --> 08:23.620
Yes.

08:24.070 --> 08:25.990
So first let's get the.

08:26.020 --> 08:28.450
Or maybe I'm going to call it expires.

08:28.450 --> 08:29.890
This would be quicker.

08:30.010 --> 08:33.880
And now we should return.

08:34.390 --> 08:40.750
So if it's not set if expires is undefined.

08:43.690 --> 08:50.680
Or the current time is after the expiry date.

08:52.210 --> 08:54.610
This means the token is expired.

08:54.640 --> 08:59.530
Now obviously we're going to test this functionality okay.

08:59.560 --> 09:08.230
So this here is implemented I might reformat it slightly which didn't really help a lot.

09:08.920 --> 09:10.240
Maybe let's do it like this.

09:10.240 --> 09:12.060
So you can see everything.

09:13.050 --> 09:15.180
Okay, so we are getting the current token.

09:15.180 --> 09:18.630
We are generating the current token.

09:18.660 --> 09:21.150
What else do we need.

09:21.180 --> 09:24.240
So we need the verification.

09:24.750 --> 09:27.540
Where is the verification.

09:27.570 --> 09:32.130
Yes I mean this function validates CSRF token.

09:32.160 --> 09:41.370
That is a function that made sure that the valid token was sent.

09:43.860 --> 09:44.910
Okay.

09:45.090 --> 09:48.570
So we need to add another public method.

09:49.380 --> 09:52.980
So this would be public static function.

09:53.130 --> 09:56.880
Let's call it verify.

09:57.090 --> 10:02.340
And I think that we actually have couple of options.

10:02.820 --> 10:13.140
So we can either just assume how the field with the token is called or where do we get the token from?

10:13.170 --> 10:21.600
Or we can explicitly, um, allow users to pass the token like we did in this function.

10:21.600 --> 10:26.550
So let's just try those options.

10:26.550 --> 10:30.540
So we allow to verify a specific token.

10:30.540 --> 10:38.520
But also we can actually get the token from both the postdata or even from the header.

10:39.420 --> 10:45.150
So we're gonna try a couple of ways to retrieve the CSRF token.

10:46.380 --> 10:51.480
But the first thing is we should get the current HTTP method.

10:51.480 --> 11:01.380
We haven't been doing that previously, but we shouldn't verify the CSRF token for some specific HTTP

11:01.380 --> 11:02.430
methods.

11:02.850 --> 11:11.190
So if the method is in the specific array, which is get or head or options.

11:11.610 --> 11:17.820
So those methods are called idempotent.

11:17.820 --> 11:26.730
And they should guarantee that whenever you call them one time and then another time, the results should

11:26.730 --> 11:28.110
always be the same.

11:28.110 --> 11:31.890
And also those methods are called safe.

11:31.920 --> 11:37.950
It means when you have requests with those methods, nothing should change on the server.

11:38.190 --> 11:43.560
And in that case we just verify the token immediately.

11:43.560 --> 11:47.670
We say true, which means there is nothing else to verify.

11:47.940 --> 11:52.530
Now let's get the CSRF token.

11:53.010 --> 12:02.970
And I think that we should first try and get it from this argument if anyone wants to verify a specific

12:03.000 --> 12:03.600
token.

12:03.600 --> 12:07.080
But we can also simplify that for the users.

12:07.080 --> 12:15.800
So it's either explicitly passed or we can take it from the post data which should have a specific name,

12:15.800 --> 12:20.330
maybe underscore, token, or even.

12:20.360 --> 12:25.130
Alternatively, we can get it from a header.

12:27.380 --> 12:29.570
So we can pass headers with the.

12:29.600 --> 12:37.910
HTTP prefix and then goes the header name which can be x which is typically used for custom headers

12:37.910 --> 12:40.550
CSRF token.

12:40.550 --> 12:44.750
We're gonna try all those different possibilities.

12:45.290 --> 12:48.830
And only the last one is null.

12:49.700 --> 12:53.810
So this null coalescing operator works that it takes this value.

12:53.810 --> 12:55.940
If it's null it takes that value.

12:55.940 --> 13:04.280
If it's null, it takes the next value or ends up with null if none of those could be matched okay.

13:04.310 --> 13:09.260
So at this point we should verify the token.

13:09.260 --> 13:22.700
So first the token cannot be null and the next step is to see if the token is not expired.

13:22.790 --> 13:27.050
So we should do static is token expired.

13:27.860 --> 13:35.750
So that's another condition that basically makes this token pass the verification.

13:36.350 --> 13:39.590
And what else do we have.

13:39.590 --> 13:42.050
So we checked for the token expiry.

13:42.050 --> 13:43.550
And then yeah.

13:43.550 --> 13:51.020
So finally the final condition is to check if those two generated hashes are equal.

13:52.130 --> 13:58.880
So we can use hash equals and we compare the start token.

14:00.920 --> 14:02.870
Which we get from the session.

14:02.870 --> 14:08.270
So we can get session CSRF token.

14:12.020 --> 14:13.400
And token.

14:16.810 --> 14:26.890
And we compare it with the token that we got from either bank passed to this method, or from the Post

14:26.890 --> 14:29.530
data, or from a header.

14:31.270 --> 14:33.400
Okay, so the token needs to be defined.

14:33.430 --> 14:41.290
Then the token can't be expired and it needs to be exactly the same as the one stored in the session.

14:41.320 --> 14:47.740
So if this is true, we just regenerate the token for the next use.

14:47.740 --> 14:52.090
So we can call generate token and we return true.

14:52.300 --> 14:55.510
Otherwise we just return false.

14:57.070 --> 15:02.470
And I think that this is a complete implementation.

15:03.190 --> 15:08.050
What we can do here right now is a little bit cleanup.

15:08.050 --> 15:12.580
So let's say that the.

15:15.040 --> 15:22.900
Token Field name could be just underscore token.

15:22.900 --> 15:26.590
And we should be storing that inside the constant.

15:26.590 --> 15:29.800
So it shouldn't be hidden somewhere in the code.

15:30.340 --> 15:34.570
So it's token field name.

15:36.790 --> 15:41.350
And I think that everything else should be fine.

15:41.350 --> 15:45.880
So we have created this class.

15:45.880 --> 15:51.520
It's more or less the same as the code we had in the previous project.

15:51.520 --> 15:54.400
But as you see it's not identical.

15:54.400 --> 15:56.320
There are some differences.

15:56.650 --> 16:05.650
But now let's take a short break and in the next one we're going to add this CSRF token into the forms

16:05.650 --> 16:06.160
that we have.

16:06.160 --> 16:09.280
I think that we currently only have the sign in form.

16:09.490 --> 16:15.850
And then later on in the course, we're also going to see a better way of using CSRF tokens to make

16:15.850 --> 16:17.890
it really fully automatic.
