Before going live with my website, i made some thoughts about security:
This question is about understanding the Processing in PHP and not strives for a solution in securing the form.
Consider this barebone script which is completely insecure against xss and
sql injections if provided.
<?
if ($_POST['submit']=="1"){
$input = $_POST['input'];
echo "echo the input: ".$input."<br/>";
}
?>
<form action="<? $PHP_SELF;?>" method="POST">
<input type="text" name="input" value="<? echo $_POST['input'];?>"/>
<input type="hidden" name="submit" value="1"/>
<input type="submit" value="submit"/>
</form>
i am wondering why such an injection like this does not work (in the field input):
";unset('index.php');
i am naively thinking the "; would end the echo and than proceed with the code.
Actually i am very happy this does not work but i would like to know why.
In SQL kind of this would actuall work ' OR 1'.
i know to secure this with addslashes or htmlspecialchars but this is not the question. I want to gain an inside of how php works in processing this.
thanks
The content of $_POST array elements are strings. So, whenever you submit ";unset('index.php');" (btw, doesn't unset work on variables?) you actually send that as a string, not as PHP executable code.
Unless you're using eval(), you don't need to fear about php code being evaluated.
Another thing, don't use addslashes() to secure queries, but use your library's dedicated function, such as mysql_real_escape_string() for mysql. Or better use query bindings with prepared statements and parametrized queries.
It would work if you put it through eval(), but otherwise it's just a string like any other.
Related
I'm new to web security.After spending time reading some blogs and community sites like SO,I have found some techniques to be safe from XSS Attack and SQL Injection.But the problem is,most of that security related questions are very old.So,my question is
does my following code has any major security holes that can be bypassed by amateur or mid-level attacker(hacker).
Is there anything else I can do to be safe from attack?By the way,I'm using HTMLPurifier to be safe from XSS Attack
PHP
require_once '/path/to/HTMLPurifier.auto.php';
$connect_dude=mysqli_connect('localhost','root','','user');
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
if(isset($_POST["sub"])){
$name=$_POST["namex"];
$email=$_POST["email"];
$ques=$_POST["ques"];
$clean_name = $purifier->purify($name);
$clean_email = $purifier->purify($email);
$clean_ques = $purifier->purify($ques);
$stmt = mysqli_stmt_init($connect_dude);
if(mysqli_stmt_prepare($stmt, 'INSERT INTO question (name,email,question) VALUES(?,?,?)')) {
mysqli_stmt_bind_param($stmt, "sss", $clean_name, $clean_email, $clean_ques);
mysqli_stmt_execute($stmt);
}
}
HTML FORM
<div id="form">
<form id="sub_form" action="ask.php" method="post" enctype="multipart/form-data">
<p id="nam" class="indi">Name</p><input type="text" id="namex" name="namex" placeholder="Your Name" required></br>
<p id="ema" class="indi">Email</p><input type="text" id="email" name="email" placeholder="Email" required></br>
<p id="que" class="indi">Question</p><textarea id="ques" name="ques" placeholder="Question" required></textarea></br>
<input type="submit" id="sub" name="sub" value="Send">
</form>
</div>
The SQL stuff is fine, parameterised queries are the best-practice approach to prevent SQL injection.
The approach to XSS is... a bit weird.
HTMLPurifier is of use where you want to allow the user to input limited HTML markup. That can be reasonable for formattable freetext fields (like I'm guessing ques is) if you can't be bothered to go as far as providing your own custom mini-markup language like Markdown.
But do you really want the user to be able to input markup for all fields, including their name and e-mail address? Should I be able to have the name “Edward Boing Jr”? Are users going to have to enter & every time they want to use an ampersand?
A better approach is usually to accept plain text as it is, and then HTML-escape it at the point you insert it into an HTML page (eg with <?php echo htmlspecialchars($value); ?>) so that the exact string entered by the user appears in the page. The fields where you deliberately allow markup (and so use HTMLPurifier instead of htmlspecialchars) are typically very much exceptional cases.
Note that if you are injecting into other contexts you need different escaping functions: for example if you are injecting into a JavaScript string in a <script> block then you need JS-string escaping and neither htmlspecialchars nor HTMLPurifier will help you with that.
Perhaps testing if each of the post variables are set and not just the sub one. Also, checking them in javascript as well before sending to php to rid the post of any unwanted characters. You can regex and test for empty strings in javascript for example.
The most checks - the better.
You can also use names that are not so common (abrv_page_name_email instead of simply "email").
Lots of stuff.
Regex and mysqli_real_escape_string are also common practice.
Is there a difference where I place my strip_tags and htmlspecialchars tag's? I read that Example 2 is better than Example 1.
But I don't understand how that can be the case, aren't these the same thing? I don't know if it also makes a difference that I am setting it back into a $_POST[] variable.
In my case, it's much easier to use Example 1, because no matter where I use $_POST['test'], I know it's safe... while I need to find ever instance that I echo $_POST['test'] and put the tags around it for Example 2.
Is one truly version safer against XSS Leaks?
Example 1:
<?php
$_POST['test'] = htmlspecialchars(strip_tags($_POST['test']));
// other code
<form action="" method="POST">
<input type="hidden" name="test" value="<?=$_POST['test']?>" />
</form>
?>
Example 2:
<?php
// other code
<form action="" method="POST">
<input type="hidden" name="test" value="<?=htmlspecialchars(strip_tags($_POST['test']))?>" />
</form>
?>
Both examples are equal (in output).
The problem I can see is that example #1 overwrites the $_POST data.
I would advise against doing so because you cannot restore the original data at a later point in the script (e.g. if you wish to save the data into a database or output it in a non-HTML context).
I somehow misunderstood the question, but this part of my old answer is still applicable.
They are two different functions.
In your case you should only use htmlspecialchars() since this function is meant to escape special HTML characters (<, >, ").
strip_tags() on the contrary strips HTML tags (and some other stuff, see the docs). Do you really want this behavior? I doubt that. Stripping HTML tags differs from escaping them insofar that it really removes the tags. Escaping only "escapes" them so that the browser renders them as normal text.
This part of code prevent XSS perfectly.
<?php
$myVar = htmlspecialchars($_POST['test']);
// other code
<form action="" method="POST">
<input type="hidden" name="test" value="<?php echo $myVar; ?>" />
</form>
?>
I use it like this
$this->message = htmlspecialchars(strip_tags($this->message));
If you have to use $_POST['test'] in multiple spots I would use example 1 since you wont have to process the other functions (strip_tags, htmlspecialchars) over again sanitizing the same data you already have.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What are the best practices for avoiding xss attacks in a PHP site
I have a form that user can fill in their personal information. The user submits the form and A web service will process these information and store the information in mysql database.
But what if users enter html tag, php code, or javascript in the input field. I would like to prevent that. I know in javascript there's a method call escapehtml, in php it's strip_tags.
I just want to know the correct way of disabling the abilities to type html, php, script from input field. Do I use strip_tags for all input I received?If I use strip_tags, how to disable script? Or there is away to do it in mysql?
Thank you
This is the form:
<div>
<label class='info-title whitetext' for="name">Full Name: </label>
<input type="text" name="name" id="name" size='25' maxlength="100" required />
</div>
<div>
<label class='info-title whitetext' for="phone">Phone: </label>
<input type='text' pattern='\d+' name='phone' id='phone' size='25' maxlength='12' />
</div>
<div>
<label class='info-title' for="email">Email: </label>
<input type="email" name="email" id="email" size='35' maxlength="60" required />
</div>
<div>
<label class='info-title' for="address">Address: </label>
<input type="text" name="address" id="address" size='45' maxlength="50" required />
</div>
Try htmlspecialchars($string);
That will encode all the HTML tags to character codes (<div> would become <div>, which will be displayed without being parsed as html) This way, script tags cannot be created as well.
Be sure to clean the content before supplying it to a database though, for example by escaping with mysqli_escape_string() (others will probably advice you to use prepare statements).
It is most likely not best practice to put HTML character encoded strings into the database, as it simply increases the string size unnecessarily. (And it doesn't provide protection against SQL injection on its own)
Personally, I just like to do $out = str_replace("<","<",$in). It provides the least possible disruption for the user, and they are most likely to get out what they typed in.
If the user input may end up in an HTML attribute (for whatever reason), you should also replace " with ".
Never put user-supplied content into a <script> tag, and never save it to a file without first performing the replacements.
You cannot disable "the abilities to type html, php, script from input field", unless you check users' input in real time and specifically block them when you detect that a tag is entered. Yet I don't see a reason why anyone would want that, the proper way is to properly process users' input when submitted.
For html tags or php codes or things like that you can definitely use escapehtml or strip_tags, but if you are later putting the content into mysql, I have to remind you of sql injection attack.
If you are not familiar with the term, users can type in mysql queries that interfere with your sql queries. If we blindly insert user provided content into our "INSERT" statements, those statements might be altered by sql keywords in user's input.
For ways to prevent sql injection attack, you can take a look at wiki's page for a good start: http://en.wikipedia.org/wiki/SQL_injection#Mitigation
When I save this string in PHP:
John: "Yes you can".
In my database is saved as:
John: \
How can I save these strings with " ( without deleting " obviously ).
This is my php code:
$titlepost= mysql_real_escape_string($_POST['title']);
$query = "INSERT INTO `titles` (`title`) VALUES ( '".$titlepost."')";
$res = mysql_query($query) or die("Failed".mysql_error() );
echo $titlepost;
output:
John: \\
FORM:
$title = mysql_real_escape_string($_GET['title']);
<form method="post" action="title.php?done=yes" enctype="multipart/form-data">
<input type="text" size="25" name="title" <?php echo "value=\"".$title."\""; ?> >
<input id="starit" name="submit" value="titleit" type="submit" />
</form>
Your problem has nothing to do with PHP or MysQL.
It is as silly as very simple HTML syntax rule.
It is quite obviously that the code
<input value="John: "YES you can>
will show only quoted "John: " part.
To make it correct, one have to encode special symbols in the value
$titlepost = htmlspecialchars($titlepost,ENT_QUOTES);
?>
<input type="text" name="title" value="<?=$titlepost?>">
As for the slashes - it is silly excessive quoting issue. just quote your strings only once and make sure you have magic_quotes_gpc turned off
If you really just get John: \ in your database, it sounds like you are using magic quotes (that causes you do insert backslashes in the database since you are escaping the escaped string) and the column size is way too small (that's why anything after the backslash is missing).
Try this:
if(get_magic_quotes_gpc()) $_POST = array_map('stripslashes', $_POST);
$titlepost = mysql_real_escape_string($_POST['title']);
This ensures that $_POST does not contain any magic-quotes-escaped data which would break after using mysql_real_escape_string.
Try using prepared statements from PDO
http://php.net/manual/en/pdo.prepared-statements.php
The parameters to prepared statements don't need to be quoted; the driver automatically handles this. If an application exclusively uses prepared statements, the developer can be sure that no SQL injection will occur (however, if other portions of the query are being built up with unescaped input, SQL injection is still possible).
Here's what I am doing,
<?php
if(isset($_POST['submit'])){
$text_area= mysqli_real_escape_string($dbc, strip_tags(trim($_POST['text_area'])));
echo $text_area;
}
?>
<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>" >
<input type="textarea" name="text_area" style="width:280px;height:90px" id="myTextarea" />
<input type="submit" name="submit" Value="Submit"/>
</form>
But whenever I try to insert something like this: "Hello World" or 'Hello World', it outputs: \"Hello World\" or \'Hello world\'
where am I going wrong?
That's because you using the mysql-real-escape-string function. Use the stripslashes function on your data before displaying it to remove the slashes.
It seems you are outputting the value from the mysqli_real_escape_string method that escapes the string value for a SQL query to avoid SQL Injection. If you simply want to output anything that was inputted into the textarea then you can just purely show the value from the $_POST array but BEWARE if you don't do any checks you can easily fall victim to someone inputting some javascript etc. and have it appear on the page.
So for example to output just the pure text you sent to the server.
trim($_POST['text_area'])
and then you can call mysqli_real_escape_string again while building your query to make the string safe and avoid some common attacks.
You are using mysqli_real_escape_string incorrectly - it serves no purpose here.
Do not use it in this context, and the problem will go away. Use it only when entering data into a database.