I've read a couple of related questions on this, but they don't answer my question directly. Developer tools like Firebug allow anyone to see and manipulate form data before a form is sent. A good example of this is adjusting the value of a hidden "member ID" field so that the form submission is credited to another user.
What are the best ways to prevent this type of tampering? My research suggests moving sensitive form inputs to a server-side script, but are there any other options or considerations?
I'm familiar with PHP and jQuery, so my ideal solution would use one or both of those languages.
You can't use jQuery for security since it's all handled on the client side.
In your example just use a PHP session in staed of a hidden input field, because as you rightfully noted this can be manipulated.
Using sessions would look something like the following:
login page
<form action="login.php" method="post">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" name="submit" value="submit">
</form>
login.php
// you have to include this on every page to be able to user sessions.
// also make sure that you include it before any output
session_start();
//Always sanitize the user input before doing any db actions.
//For example by using: `mysql_real_escape_string()` ( http://php.net/manual/en/function.mysql-real-escape-string.php ).
// check user credentials against db
$_SESSION['user'] = $dbresult['username'];
page-where-userid-is-required.php
session_start();
if (!isset($_SESSION['user'])) {
// user is not logged in!
} else {
// use user info to place order for example
}
The session will be active until the user closes his browser / until the session expires (which is a PHP setting)
The above is just some sample code to give you an idea.
It works smaller projects, however as projects get more complex I would suggest going for the MVC (Model, View, Controller) way. ( http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller )
But that's just a whole other story :)
Here are a few basic suggestions:
You need to validate form inputs using a server-side (PHP) script.
Instead of relying on sensitive pieces of information, such as member ID, from the form you could instead cache such data in your server session. That way there is no way for a malicious user to change the data on the fly.
You can still use jQuery validation as a convenience to catch basic input problems, but you can only trust data that is validated using server-side code.
Related
I need to make a completely normal restricted area of my website accessible only to registered, logged-in members. The restricted pages will be pulling data from a MySQL database using PHP.
I have been searching for a way to do this, finding many useless results. Most of what I've found is either insecure, outdated or just deals with one very specific area of the process. It is incredibly frustrating spending hours studying a method of doing this, only to find out that they've used some insecure method and it's completely useless. So I'm hoping to get the opinions of the experienced stackoverflow community to point me in the right direction.
So my question is this:
Knowing that hundreds of thousands of websites have exactly the same "register, log in, grant access to pages A, B and C, log out" combination of events, is there a universally accepted way of setting this up (and if not, why not)? Is this: http://www.wikihow.com/Create-a-Secure-Login-Script-in-PHP-and-MySQL a "good" way of achieving this (assuming I figure out how to get it to work)?
The pages/database will not hold anything like credit card numbers or other sensitive information, so I don't think I'll have thousands of hackers constantly attacking the site, but I obviously want to maintain a reasonable level of security. I've been careful to avoid the potential of SQL injection attacks on the database side of things.
Many thanks,
Paul
try this.
login.php
<form action="check.php" method="post">
<table border="0" cellpadding="0" cellspacing="0" style="margin-left:auto; margin-right:auto;">
<tr><td>Nickname:</td><td><input type="text" id="usernaame" name="usernaame"></td></tr>
<tr><td>Password:</td><td><input type="password" id="passworrd" name="passworrd"></td></tr>
<tr><td colspan="2"><input type="submit" value="Login" class="button"></td></tr></table>
</form>
<br><button>Register</button></div>
check.php
<?php
session_start();
$user = htmlspecialchars(addslashes($_POST['usernaame']));
//you can also edit password encryption
$password = htmlspecialchars(addslashes(md5(sha1($_POST['passworrd']))));
//put here your query
$query = mysqli_query();
if(mysqli_num_rows($query)=="1"){
$_SESSION['logged'] = $user;
}
else{echo 'Data is incorrect';}
?>
index.php (where protected content is)
<?php
session_start();
if(!isset($_SESSION['logged'])){echo 'Please login';}
else{
//your private content here
}
?>
I'm building a site where staff will have their own section of the site: example.com/jones, example.com/smith, etc. jones and smith are template groups with the same templates inside (using Stash and Low Variables to keep it all DRY). Some users will have different needs for privacy. On one end their section will be public. On the other end some users will need to administer who can access their content (using Solspace friends).
However in the middle of that range are some who just want to protect against any random person seeing their content. I don't want to use members/member groups to manage this. I don't want visitors to need to register to see the content. A shared member account is an option, but we ruled that out because of other issues (what if the password is reset, comments being left under the same account, etc.
What we would like is to password protect the template group. The staff can let people know where to see their page, and let users know what the password is. This is all possible on a server level, but is is possible to allow the user to directly manage the password? Anything we can do to minimize how much we need to have hands on admin of this the better. A custom field and an add on that allows for this kind of security? I didn't see anything on Devot-ee and the methods on the forums don't do this. Bit of a longshot, but figured I'd ask.
Since you said you didn't want to be tied to actual member accounts and were OK with using a custom field to store an editable password...
I just recently did something similar that protected a group of entries using a custom field. It is similar to the approach outlined in this "Password Protected Content Made Simple" article. But instead of using PHP in the template I used Mo' Variables. And instead of using url_title I used a custom field (called client_password below).
In addition, I used the Session Variables plugin to check if the user was already "logged in" on subsequent page loads, preventing them having to enter the password again and again.
{!-- PASSWORD REQUIRED --}
{if client_password != ""}
{!-- if passed show content and set session --}
{if post:password == client_password}
{!-- protected content here --}
{!-- set session --}
{embed='embeds/_set_session' entry_id="{entry_id}"}
{!-- if session is valid show content --}
{if:elseif "{exp:session_variables:get name='logged_in'}" == "{entry_id}"}
{!-- protected content here --}
{!-- if failed show login --}
{if:elseif post:password != "" AND post:password != client_password}
<div id="protected">
<p>Incorrect password. Please try again.</p>
<br>
<form action="" method="post">
<strong>Password</strong><br />
<div>
<input name="password">
</div>
<input type="submit" class="submit" value="submit">
</form>
</div>
{!-- if first attempt show login and prompt --}
{if:else}
<div id="protected">
<p>This page is password protected. Please provide the password.</p>
<br>
<form action="" method="post">
<strong>Password</strong><br />
<div>
<input name="password">
</div>
<input type="submit" class="submit" value="submit">
</form>
</div>
{/if}
{!-- NO PASSWORD REQUIRED --}
{if:else}
{!-- protected content here --}
{/if}
I wanted to update this with the code I'm using to get htaccess and htpasswd working to protect by template group. It can be used in the same way as Alex's, but is an all or nothing approach. It has its own advantages, and disadvantages, but wanted to share it as an option.
First, I am using the native template behavior: example.com/group/template/url_title. I want to password protect some template groups, but outside of EE's members and member groups. ie a single user and password.
My htaccess file looks like this (from http://perishablepress.com/enable-file-or-directory-access-to-your-htaccess-password-protected-site/):
# We set some variables, matching URL's for which we do not wish to active
# the password protection
SetEnvIf Request_URI "^/privategroup.*$" private
# Setup the password protection
AuthName "Password Needed"
AuthGroupFile /dev/null
AuthType Basic
AuthUserFile /Users/user/Sites/example/.htpasswd
Require valid-user
# Add the exceptions for matched URL's
Order Deny,Allow
Deny from env=private
Satisfy any
The htpasswd file should be above webroot, but for testing I left it in webroot. The AuthUserFile line tells Apache where to find the file with the usernames and passwords. This must...MUST be an absolute path. I was using relative and got 500 errors. You need to use terminal or some other tool to make this file. http://developer.apple.com/library/Mac/#documentation/Darwin/Reference/ManPages/man1/htpasswd.1.html
The result is that directory requires a username and password. Right now it will accept any valid user in my htpasswd file. However I can change that by specifying a specific user (require user john tim lisa) or groups.
There you have it. Keep people out of specific template groups without using any native EE functionality.
I will be honest, I'm not sure if this fits your needs or not. It's not clicking that it will though, I've never tried it before and would need to actually give it a go to know for sure that it does or does not fit.
I will post it just the same as it may help you or someone else down the road:
http://koivi.com/ee-entry-auth-dir/
Have you looked at using the HTTP Authentication option under Template Access Restrictions? It uses a member password for authentication, but doesn't require the member to actually be logged-in.
You say you "don't want to use members/member groups to manage this", but then that you want to "allow the user to directly manage the password" ... surely using the built-in member system is the easiest way?
I have implemented CSRF protection on my website using a CSRF token in a hidden input field in my forms. However at some places in my website I don't use a form for certain actions, e.g. a user can click a link to delete something (e.g. /post/11/delete). Currently this is open to a CSRF attack, so I want to implement a prevention for these links. How can I do this? I can think of two possible ways:
Make all links (which for example delete something) into tiny forms with only one hidden field (the CSRF token) and one submit button (styled as a normal link).
Add the CSRF token to the query-string
I don't like either of those options:
Styling a submit button to act exactly as a link might have some issues getting it correct (cross platform)?
Although it will never be picked up by search engines and don't like some random string in my URL (just aesthetics).
So is there a way I'm overlooking or are those two my options?
Add a token to your links.
styling submit to look like link is not hard. Though there will be issues with middle click or 'copy link location' command. Obviously.
facebook / google are not afraid of putting 'random strings' in urls. Neither should you. (Adding nofollow to those links, and excluding them in robots.txt should solve your fears with SEO. That is in case you for some reason show REST links to guest users / search engines).
If you really don't want URL parameters with long random values, you could implement a confirmation page for each Delete action, and have a form with your hidden field there.
Requests received at /post/11/delete without valid token will make the server respond with the confirmation page.
Requests received at /post/11/delete with valid token will trigger the deletion.
Best practice is to not perform updates via a GET operation.
Here's a clever little script that will hook into all of your links and make them POST a single hidden variable in addition to the payload in the querystring. Hope this is helpful!
document.ready = function () {
var makeLinkPost = function(link) {
var handleClick = function(event) {
event.preventDefault();
$("<form action='" + this.href + "' method='POST'><input type='hidden' value='CSRF'/></form>'").appendTo("body").submit();
}
$(link).click(handleClick);
}
$("a").each(function() {
makeLinkPost(this);
})
}
Examine this example. It is in PHP, but you should be able to pick up what is happening if you don't know PHP.
echo 'You searched for "' . $_GET['q'] . '"';
Now, obviously, this is a bad idea, if I request...
http://www.example.com/?q=<script type="text/javascript">alert('xss');</script>
OK, now I change that GET to a POST...
echo 'You searched for "' . $_POST['q'] . '"';
Now the query string in the URL won't work.
I know I can't use AJAX to post there, because of same domain policy. If I can run JavaScript on the domain, then it already has security problems.
One thing I thought of is coming across a site that is vulnerable to XSS, and adding a form which posts to the target site that submits on load (or, of course, redirecting people to your website which does this). This seems to get into CSRF territory.
So, what are the ways of exploiting the second example (using POST)?
Thanks
Here is an xss exploit for your vulnerable code. As you have aluded to, this is an identical attack pattern to POST based CSRF. In this case i am building the POST request as a form, and then I call .submit() on the form at the very bottom. In order to call submit, there must be a submit type in the form. The post request will immediately execute and the page will redirect, it is best to run post based csrf of exploits in an invisible iframe.
<html>
<form id=1 method="post" action="http://victim/vuln.php">
<input type=hidden name="q" value="<script>alert(/xss/)</script>">
<input type="submit">
</form>
</html>
<script>
document.getElementById(1).submit();//remote root command execution!
</script>
I also recommended reading about the sammy worm and feel free to ask any questions about other exploits I have written.
All I would need to do to exploit this is to get a user to click a form that sends a tainted "q" post variable. If I were being all nasty-like, I wouldcraft a form button that looks like a link (or even a link that gets written into a form POST with Javascript, sort of like how Rails does its link_to_remote stuff pre-3.0).
Imagine something like this:
<form id="nastyform" method="post" action="http://yoururl.com/search.php">
<input type="submit" value="Click here for free kittens!">
<input type="hidden" name="q" value="<script>alert('My nasty cookie-stealing Javascript')</script>" />
</form>
<style>
#nastyform input {
border: 0;
background: #fff;
color: #00f;
padding: 0;
margin: 0;
cursor: pointer;
text-decoration: underline;
}
</style>
If I can get a user to click that (thinking that he's clicking some innocent link), then I can post arbitrary data to the search that then gets echoed into his page, and I can hijack his session or do whatever other nasty things I want.
Post data isn't inherently more secure than get data; it's still user input and absolutely cannot be trusted.
CSRF attacks are a different class of attack, where some legitimate action is initiated without the permission of the user; this has the same sort of entry vector, but it's a classic XSS attack, designed to result in the injection of malicious Javascript into the page for the purpose of gaining session access or something similarly damaging.
Using Microsoft's AntiXssLibrary, how do you handle input that needs to be edited later?
For example:
User enters:
<i>title</i>
Saved to the database as:
<i>title</i>
On an edit page, in a text box it displays something like:
<i>title</i> because I've encoded it before displaying in the text box.
User doesn't like that.
Is it ok not to encode when writing to an input control?
Update:
I'm still trying to figure this out. The answers below seem to say to decode the string before displaying, but wouldn't that allow for XSS attacks?
The one user who said that decoding the string in an input field value is ok was downvoted.
Looks like you're encoding it more than once. In ASP.NET, using Microsoft's AntiXss Library you can use the HtmlAttributeEncode method to encode untrusted input:
<input type="text" value="<%= AntiXss.HtmlAttributeEncode("<i>title</i>") %>" />
This results in
<input type="text" value="<i>title</i>" /> in the rendered page's markup and is correctly displayed as <i>title</i> in the input box.
Your problem appears to be double-encoding; the HTML needs to be escaped once (so it can be inserted into the HTML on the page without issue), but twice leads to the encoded version appearing literally.
You can call HTTPUtility.HTMLDecode(MyString) to get the text back to the unencoded form.
If you are allowing users to enter HTML that will then be rendered on the site, you need to do more than just Encode and Decode it.
Using AntiXss prevents attacks by converting script and markup to text. It does not do anything to "clean" markup that will be rendered directly. You're going to have to manually remove script tags, etc. from the user's input to be fully protected in that scenario.
You'll need to strip out script tags as well as JavaScript attributes on legal elements. For example, an attacker could inject malicious code into the onclick or onmouseover attributes.
Yes, the code inside input boxes is safe from scripting attacks and does not need to be encoded.