So finally, with the CSRF protection, it's time that we verify the token.
So we have the logic already inside the contact post route handler.
Just this function is not implemented.
Let's jump to it right now to verify the token.
We're going to use hash function from PHP, which is a safe way to compare tokens, passwords, or any
other hashed strings that need to be compared securely.
Now, it's important to just pass this token that was generated as the first argument, and the second
one should be the token that was sent or provided by the user.
In our case, this means the second argument would be the token sent with the form.
So since we are all about security, it's also important not to use the normal string comparison operator,
but the safe equivalents that are used and created for security purposes.
So let's get started with this function.
Now the first step here is to get the current token and time stored in the session.
Since we already used the token as an argument name, let me call this variable stored token.
And if any of those is not set.
So either stored token is not set or time is not set.
We just return false verification has failed.
Next up, if the token is expired we are using time for that.
We return false.
And it might also be a good idea to remove both values from the session.
So let me use On set for both operations.
So both the CSRF token and CSRF token time should be removed.
Now we can optionally think about using this function for both and accepting the token and time as parameters.
If any of those would be null, then we would be removing from the session instead.
Let's leave it for the end of this video for now.
Let's just make sure we remove those values from the session and return false.
Now at this point we need to validate the token if it's exactly the same as the one we have stored,
because we obviously have it and it is not expired.
So let's see if the token is valid.
We're going to use hash equals.
The first value is the start token and the second one is the user passed token, or just use an empty
string.
But I think that at this point there is no chance that the token no, there actually is a chance that
the token is null.
So yes, let's pass an empty string.
Now those can't be the same because the start token will always contain a value.
So that was the final check.
If the token was valid, we need to generate a new token for the next form submission.
And we just return the value of the valid variable.
So that was the final result okay.
So we just need to try this.
But let's also move this code into a common function because we've got them for a reason.
So here, if the token would be null.
We're just going to unset those values and return.
Otherwise we generate a new token.
This means that the token can be null.
So essentially passing null means that I just want to remove the token altogether from the session.
And now I don't need to worry about unsetting those.
I can just say set CSRF token and time and I just pass null.
This means remove it from the session.
So before we test that, I think I might have an issue here.
So in the template I'm Sending the token using this field name.
CSRF token.
On the other hand, in the root handler I'm using the underscore notation.
Let's fix that.
Close those files and let's refresh the form.
And let me just say this should work because indeed it should work.
There is our message.
Now let me first do a quick test that will generate this token for a short time.
Five seconds.
So we can see how it behaves when it expires.
Jump to a contact form.
We've got the token generated.
No rush here.
I'm slowly gonna fill it out so it takes at least five seconds.
I write this would fail.
And this has failed because I set the token lifetime for five seconds.
So before I manage to send the form, it has expired.
Now, obviously it doesn't make any sense for the token to be that short, but I just wanted to demonstrate
that the expiry time of token is indeed real, and it expires after five seconds.
Let's bring it back to something sensible, which is 30 minutes.
And the ultimate test should be testing our malicious website that previously has sent the form using
the beautiful kitten.
Let's do it next.
So again, I'm just opening this attack file with the kitten, and I think it takes around eight seconds
before it tries to submit the form.
And as you see, we are protected because that website can't have the token because we always generated
on our page.
Now, if you are thinking if this malicious person is able to grab your token somehow and also send
it together with the form to validate the form, well, there is no way because the token, the CSRF
token, is being generated and kept per user inside this user.
Individual session data.
You need to understand that sessions are unique per user.
There is no way to share the session between different people.
Now there are some things that we would have to remember about with this setup, and it is to verify
the CSRF token inside the root.
If you don't do that well, there is no protection.
Additionally, you always need to generate the token inside the form.
So that's another thing and you need to include it inside the form.
This can be solved differently.
You might have some function that will just generate this output.
That may be much easier to use than having to worry about adding this input every single time, and
also that token verification.
Well, this can also be generic.
For example, you might add some generic case in the router that checks if the specific request is of
type post, and then it always asks or verifies the CSRF token.
So this would be most definitely a more generic approach that will by default protect all the routes
which are of type post, which is typically used to send forms.
But I'm leaving that up to you to explore this on your own.