Okay guys.
So next up our next topic is adding the CSRF tokens into our app.
Well fortunately we have already implemented that in the previous project.
But then we were just using functions.
But what we can use is well the logic.
We don't really have to rethink it from scratch.
We don't have to invent anything.
We already know more or less how this should be implemented.
So consider this an exercise in which we are going to convert this code into an object oriented code.
And then we will also create a handy helper function to make it super easy to add those tokens to forms
and verify them.
Let's get started.
All right guys, let's create a service for this CSRF tokens.
Later on we might rethink our namespaces.
Not everything has to be called a service.
For now, let's just keep it this way.
That's our CSF php class.
We are adding a tag, a namespace that's app Services and that's a CSF class.
We might do it all uppercase, but maybe let's just leave it like this.
Okay.
So what things we might copy right away.
Let me define the constants we default to private.
I think it's a sensible idea to always default to private unless you need some changes later on.
Then you can change the visibility of your fields and methods.
And this would be the token length.
Let me just copy that.
The next one is the token lifetime.
This needs to be in seconds.
So I do private const.
That's also an int.
And since we are using a class I don't need this CSRF prefix.
It's obvious what I mean.
What else could I mean inside a CSRF class.
So in this case my PHP is complaining about this constant definition.
Well, the reason is simple.
Let me jump to terminal.
I'm going to show you my PHP version.
So I just have PHP 8.2.4.
It's an older one and I think I have it installed together with Samp.
When I presented how to install Samp for the other course.
Well, that's not the most recent one.
And in the PHP 8.3 or since PHP 8.3, you can add types to constants.
So that's the reason it is highlighting that in red.
So it just depends what PHP version do you have if you have 8.3 or newer, you can add those types.
I'm going to remove them now because for some reason I have an old version.
Anyway, let's continue with the logic.
Next up we should generate a token so we are fresh with token generation because this is what we did
in the Remember Me functionality.
And we're gonna generate the token the same way.
It might be also a good idea in the future to move the token generation to one place so we can generate
tokens in like one class without repeating the logic.
Let's call it generate token without parameters.
It returns a string.
So it's similar to this function.
As you see, we can easily generate a token using this constant that we're going to get from class using
token length.
Everything gets simpler with classes as here in the functions, we need to be very explicit what we
are doing and in the methods.
Well, it's part of a CSV class, so the names can really get to the point.
Like this method name generate token.
It's obvious it is a CSRF token.
Next up, the generation should also add it to the session.
Let's use the super global.
So the session um, I think we can just store an array as well.
So let's do it.
Let's just add a session CSRF token variable.
That's going to be an array here we're going to have a token that's this one.
And it needs an expiry date for that.
We're just going to get the current time.
Plus we need a token expiration time, which we have right here in seconds.
That's our token lifetime.
And we return a string from this method.
And well I'm using self.
It's better to use static.
If it is overridden in the parent class it will get the correct value.
Okay, I'm not sure why I had this semicolon in here.
So this one is fine.
Next up we need another static one called.
To fix this keyword that's function.
And this will be called get token.
So it will give you the current active token.
So um do we have a function like this.
So this would be this one.
We get the current token only if it if it's not expired.
Otherwise we need to just regenerate it.
So we're going to check if maybe we don't have a token already inside the session.
So this is CSRF token.
So that's one reason to regenerate the token.
The other one is to check if it is expired.
So we can have another method called is token expired where we don't need to pass the token because
we always get it from the session.
That's really nice about sessions that they are per user, so you don't need to worry about passing
the values around.
And in this case we're gonna generate a new token and we're going to return it which also stores the
token inside the session.
Like this.
And if we already have a token that is still valid.
We're just going to get it from this session variable, which as we already know, can be an array.
So we use this multi-dimensional array.
So this method does not exist.
It's time to add it.
I think it should be private.
So it's private.
Static function is token expired and it returns a boolean.
And we have a function like this.
Okay.
So let's uh see how this is implemented.
So we also optionally pass the time.
I'm not sure I don't remember what was the reason for it.
Anyway, let me first get the expiry date because it is actually deeply nested inside the session.
Inside CSRF token key expires.
If I'm correct, that's the key name.
Yes.
So first let's get the.
Or maybe I'm going to call it expires.
This would be quicker.
And now we should return.
So if it's not set if expires is undefined.
Or the current time is after the expiry date.
This means the token is expired.
Now obviously we're going to test this functionality okay.
So this here is implemented I might reformat it slightly which didn't really help a lot.
Maybe let's do it like this.
So you can see everything.
Okay, so we are getting the current token.
We are generating the current token.
What else do we need.
So we need the verification.
Where is the verification.
Yes I mean this function validates CSRF token.
That is a function that made sure that the valid token was sent.
Okay.
So we need to add another public method.
So this would be public static function.
Let's call it verify.
And I think that we actually have couple of options.
So we can either just assume how the field with the token is called or where do we get the token from?
Or we can explicitly, um, allow users to pass the token like we did in this function.
So let's just try those options.
So we allow to verify a specific token.
But also we can actually get the token from both the postdata or even from the header.
So we're gonna try a couple of ways to retrieve the CSRF token.
But the first thing is we should get the current HTTP method.
We haven't been doing that previously, but we shouldn't verify the CSRF token for some specific HTTP
methods.
So if the method is in the specific array, which is get or head or options.
So those methods are called idempotent.
And they should guarantee that whenever you call them one time and then another time, the results should
always be the same.
And also those methods are called safe.
It means when you have requests with those methods, nothing should change on the server.
And in that case we just verify the token immediately.
We say true, which means there is nothing else to verify.
Now let's get the CSRF token.
And I think that we should first try and get it from this argument if anyone wants to verify a specific
token.
But we can also simplify that for the users.
So it's either explicitly passed or we can take it from the post data which should have a specific name,
maybe underscore, token, or even.
Alternatively, we can get it from a header.
So we can pass headers with the.
HTTP prefix and then goes the header name which can be x which is typically used for custom headers
CSRF token.
We're gonna try all those different possibilities.
And only the last one is null.
So this null coalescing operator works that it takes this value.
If it's null it takes that value.
If it's null, it takes the next value or ends up with null if none of those could be matched okay.
So at this point we should verify the token.
So first the token cannot be null and the next step is to see if the token is not expired.
So we should do static is token expired.
So that's another condition that basically makes this token pass the verification.
And what else do we have.
So we checked for the token expiry.
And then yeah.
So finally the final condition is to check if those two generated hashes are equal.
So we can use hash equals and we compare the start token.
Which we get from the session.
So we can get session CSRF token.
And token.
And we compare it with the token that we got from either bank passed to this method, or from the Post
data, or from a header.
Okay, so the token needs to be defined.
Then the token can't be expired and it needs to be exactly the same as the one stored in the session.
So if this is true, we just regenerate the token for the next use.
So we can call generate token and we return true.
Otherwise we just return false.
And I think that this is a complete implementation.
What we can do here right now is a little bit cleanup.
So let's say that the.
Token Field name could be just underscore token.
And we should be storing that inside the constant.
So it shouldn't be hidden somewhere in the code.
So it's token field name.
And I think that everything else should be fine.
So we have created this class.
It's more or less the same as the code we had in the previous project.
But as you see it's not identical.
There are some differences.
But now let's take a short break and in the next one we're going to add this CSRF token into the forms
that we have.
I think that we currently only have the sign in form.
And then later on in the course, we're also going to see a better way of using CSRF tokens to make
it really fully automatic.