Prevent form submission from other pages - php

I have created this function:
function blacklisted_ip() {
$('form').remove();
$('.wrapper').removeClass('form-success');
$(".login_text").html("Your IP has been blacklisted");
}
that removes a HTML form - I remove the form to stop users with a blacklisted IP logging in.
I have a php script at the top of the same page that processes the login when the form is posted.
Is there also a way i can stop other pages posting to this page?
the php starts like this:
if($_POST) {
}
I thought about adding a hidden field with a value in but then thought someone will be able to view the source and just copy it?

Best way to do this is using CSRF tokens. If you're suing any frameworks the they're already implemented out of the box, if not and if you want to implement it on your own you can do it.
CSRF stands for Cross-Site Request Forgery, which is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user’s web browser to perform an unwanted action on a trusted site for which the user is currently authenticated.
Reference: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
Solution to prevent this is to have a unique CSRF tokens for each users for each form. When ever user opens the page and form is loaded you assign a token/key to that (page+form) and save that in session with expairy of your choice.
Add this token along with the form as hidden field and post that along with other datas, now when you process the form compare the token received from client side along with your sessions's token. If they match they're authenticated and if not don't process the form.
You can use any method to generate the CSRF tokens, in your case they would be just unique keys for each page+form.

Related

Can multiple submissions of PHP forms be effectively prevented with sessions without destroying the caching mechanism?

Lets say we have a certain endpoint in a Symfony CMS application for receiving form submissions (e.g. of a contact form). This endpoint sends a copy of the contact form contents to the E-Mail entered within the contact form.
As soon as an attacker finds out about how the endpoint works (which is pretty easy) he could just go behind the Captcha after validating it once and use the endpoint directly in order to send thousands of E-Mails using the sender address of the companys' mailserver (server side Captcha validation will help, but it is not a full answer to this question).
Therefore a mechanism is needed in order to prevent attackers from doing this - at least to easily. The first solution which came to my mind was tokens. The problem with tokens is that they do not play very well together with caching, implementing an ajax endpoint for tokens would just require an attacker to fetch a new token from the first endpoint and send it to the other endpoint among with new data.
So my idea is like this:
Create an ajax endpoint which creates a PHP session. It is
called via JavaScript everytime a page with a form is opened (so
there will be a PHP session whenever a form is submitted)
If the form is submitted and there is no valid session the server
instantly returns an error after sending the form
The form ID will be saved within the session. On the server side it
is validated if the form was sent by this user within e.g. the last
two minutes and if yes, form processing is denied.
The SessionService class which does session_start(); is only included in
the ajax endpoint for creating sessions as well as in the ajax
endpoint for form submissions. Therefore normal CMS pages can still be
cached as session_start(); is never called.
Is there a serious issue with this kind of implementation or is it a good solution to the problem? If you see a problem how would you solve it instead?

CSRF (Cross Site Request Forgery) does not work as expected in Laravel

I am learning Laravel using "Laravel Code Bright". In the "Form Security" section of this book, it talks about how Laravel generates secret hidden code to prevent "CSRF - Cross Site Request Forgery" when using the Form::Open() method to generate form inputs.
I tried an example to access the route that will process the form using an external form. First I did it without the "before"=>"csrf" filter attached to the route and i got the answer I was expecting, that is the external form was able to access the route.
For the second test, I added the "before"=>"csrf" filter to the route. When i clicked the submit button of the external form, the page kept on loading for a long time and it gave up without showing any results, the page was blank. It means that the "before"=>"csrf" filter prevented this external form from accessing the route.
For my third test, I copied the hidden-token of the original form (by viewing the browser's source code page) and added it to the external form and tried it again and by clicking the submit button this external form gave me the same results as the first test, that is it showed the results meaning that it was able to access the route through the hidden token I added from the original form.
My understanding is that if you add a hidden-token to your forms to prevent "CSRF" and the attacker views the browser's source page and copied the hidden-token and adds it to his form, he can still target your routes, since the hidden-token will always be visible in the browser's view source page.
My question is, is there a better way of preventing "CSRF" even if the attacker copies the hidden-token and adds to his forms?
The external form am using is outside the root folder of Laravel. I also copy the value of the "action" attribute of the original form in order to target the route of the original form. I copy it from the browser's view source page.
Your tests are correct - but your understanding is wrong.
The whole point of CSRF is to prevent a hacker from creating a form on their page that works on your page for another user. They can always copy a form that works for themselves - because they know their own CSRF code - but they can never know another users CSRF code.
Without CSRF:
The way CSRF attacks work is your website has a form to "transfer money". The attacker puts a fake copy of your "transfer money" form on his page.
If User A is logged into your website, and goes to the attackers page, the attacker can trick the user into submitting the "transfer money" form and transfer himself lots of money.
Because User A is logged into your website, the transfer form will work, since they have a valid session. But there is no CSRF check - so the hackers 'copied' form will work for User A.
But with CSRF:
The attacker copies the form from your website - but they dont know the CSRF code for User A. They only know the code for themself. They can basically* never get that code. So when User A submits the 'fake' "transfer money" form on the hacker page - it will fail - since the hacker cannot include the CSRF token since they dont know it.
This is how you protect against CSRF attacks.

Process form only if sent by server

I have some pages in my web app which deal with the sent data from a form. I want to avoid the following situation:
An user creates (in the client side) a form with the same fields that my original form and sends it to the url which process the forms. Then, my process page receives the form sent by the user and processes it.
Is there any way to do that only forms sent via my web application get processed?
An easy way is to generate a random token, set that in a session variable when you generate the form and add is as a hidden field to the form.
When the form is sumbmitted, you can check the session variable against the form field value.
That ensures that a visitor would need to request the form first but of course they could still to that programmatically, get the token and add that to the form submission.
Are the users not authenticated?
You might want to research around CSRF. There are many articles detailing how to go about that, see below:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
http://blog.ircmaxell.com/2013/02/preventing-csrf-attacks.html

How can i get the post data url on my server in php

I need to check the request Url in php. Basically i need check whether the form is post from the same server or not. I need to get the action of form in php
There is no reliable way to tell what an HTTP request was constructed in response to.
What you can do is implement defences against CSRF. This won't guarantee that the submission comes from a form on your own server, but it will prevent a third party (Mallory) from tricking a user (Alice) of your site into submitting bad data on their behalf.
When Alice arrives at your site, generate a random token and give it to her (e.g. in a session). Put a copy of that token in a hidden input in your form. If, when the form is submitted, the tokens don't match, then the request is coming from Mallory.
If the problem is that you don't trust Alice not to edit the form herself, then you can't use that as a defence.
Don't give Alice data you don't trust her with in the first place. Check the identify of users making requests before you give them access to the relevant bits of the site.
For example, if the form is the "Delete message" form and your concern is "Alice might change the ID of the message to be deleted" then check that Alice is the owner of the message with that ID when you get the request to delete it.
You are in need of a CSRF token.
When the page is requested add a string to the form, like
<input type=hidden name=token value=$token>
and save it in the database as well.
The token can be generated using something like hash of timestamp.
When the form is submitted, verify whether the token was generated by the server itself.

Prevent duplicate record insertion on refresh without redirecting

I have this bit of script:
if (isset($_POST['comment_posted'])) {
$user_comment = mysql_real_escape_string($_POST['user_comment']);
$add_user_comment = Event::addUserComment($id,$user->user_id,$user_comment);
}
After a user submits his comment, and refreshes the page, he is being presented with the "you are going to resend the post data" warning. And if the user accepts, it will re-insert the user comment.
I understand that I can prevent that by adding using the header function and redirect the member to the same page. Is it possible to solve this issue without redirecting the member?
No. You'll either do a post-redirect-get or subsequent refreshes will present this dialog to the user.
In case you chose not to do a PRG, you need to somehow detect that the submission is duplicate. One easy way is to have injected a hidden parameter with a random hash/number (e.g called token). Upon submission you'll have to check that the token you expect (which you'll have probably stored in the http session) is being sent together with the other POST parameters. On valid submission you'll remove/invalidate this token. That way when a POST comes which a non recognised token then it's most probably a duplicate or out of date request.
If you implement this correctly then you'll also make your application proof to csrf attacks.
You could set some session variable after successful submission. For each submission you check whether the variable is set or not, on you make an insertion of data.

Categories