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.
Related
On my website users can submit a form that contains their name, email, and an amount.
<input type='text' minlength='2' maxlength='30' spellcheck='false' placeholder='Elon' autocomplete='off' form='form' required>
<input type='email' minlength='6' maxlength='40' spellcheck='false' placeholder='musk#tesla.com' autocomplete='off' form='form' required>
<input type='number' step='0.01' min='2000' max='99999999.99' placeholder='$2,000.00' autocomplete='off' form='form' required>
However, instead of posting the HTML form, the values are parsed in one JS function, which then sends a string containing all of the parameters to another function that creates an AJAX request.
form.onsubmit = function(e){
const
children = this.children,
summary = this.parentNode.parentNode.children[0].innerText.split('.'),
negotiate = this.parentNode.children[1]
insert_data(`table=offers
&name=${children[0].value.toLowerCase()}
&email=${children[1].value.toLowerCase()}
&amount=${children[2].value * 100}
&sld=${summary[0]}
&tld=${summary[1]}`
)
return false
}
function insert_data(parameters, async){
async = async === undefined || async
let xhr = window.XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP')
xhr.open('POST', 'ajax.php', async)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8')
xhr.send(parameters)
}
Considering that, here's my first question: For the sake of security, should the insert_data(parameter string) be encoded, even though it is posted and not actually passed along as parameters in an actual URL?
Below is the PHP to which the AJAX request posts the data. In the script I'm trying to sanitize the data before inserting it.
Earlier today I read on SO that htmlspecialchars() and prepared statements should be sufficient, and that there isn't much else one can do, when it comes to sanitizing input. But I figure I might as well try to do everything I can.
$name = trim(strtolower(htmlspecialchars($_POST["name"])));
$email = trim(strtolower(filter_var($_POST["email"], FILTER_SANITIZE_EMAIL)));
$amount = trim(filter_var($_POST["amount"], FILTER_SANITIZE_NUMBER_INT));
$sld = trim(strtolower(htmlspecialchars($_POST["sld"])));
$tld = trim(strtolower(htmlspecialchars($_POST["tld"])));
I also read earlier that FILTER_SANITIZE_MAGIC_QUOTES is now deprecated, even though there's no mention of this at all in the documentation. Because of this, I'm wondering whether any of the following filters are also depcrecated?
FILTER_SANITIZE_EMAIL
FILTER_SANITIZE_NUMBER_INT
FILTER_SANITIZE_SPECIAL_CHARS
FILTER_SANITIZE_FULL_SPECIAL_CHARS
FILTER_SANITIZE_STRING
And my last question is, if none of the filters above are deprecated, which of the last three filters should I be using for $name, $sld, and $tld, which should be basic ASCII strings? They all seem so similar to one another...
Thanks
`table=offers&name=${children[0].value.toLowerCase()}...`
There's a problem here. If any of the values contain a & and/or =, the meaning of this query string will be altered, and at the very least you'll lose information. You need to encodeURIComponent each individual value before placing it into a query string, e.g.:
`table=offers&name=${encodeURIComponent(children[0].value.toLowerCase())}...`
You don't need to encode anything for sending it over HTTP. The TL;DR is that you must use HTTPS if you're interested in hiding the information from 3rd parties, there's no sensible way around this.
$name = trim(strtolower(htmlspecialchars($_POST["name"])));
Just… don't. Don't HTML-encode your values for storage. What if you send this value in a plaintext email, or use it in some other non-HTML context? It'll contain HTML entities. That's how things like "Dear Mr. O"Connor" happen.
Just store the plain values as is in the database. You may want to validate them, e.g. check that an email looks like an email, but you shouldn't alter the values unless you have a very good reason to.
Use prepared statements to protect against SQL injection. If you ever output those values again somewhere, encode/escape them properly at that point; e.g. htmlspecialchars them when outputting them into HTML.
See:
How can I prevent SQL injection in PHP?
How to prevent XSS with HTML/PHP?
The Great Escapism (Or: What You Need To Know To Work With Text Within Text)
When I check my script with Acunetix vuln scanner i see this XSS error :
This vulnerability affects /cms/search.php.
Discovered by: Scripting (XSS_in_URI.script).
Attack details
URI was set to "onmouseover='prompt(961413)'bad=">
The input is reflected inside a tag parameter between double quotes.
in search.php page i safe all user input with this:(safeXSS name of anti XSS function)
if (isset($_POST['search'])) {
$search = array_map ('safeXSS', $_POST);
}
else
{
$search = array_map ('rawurldecode', $_GET);
$search = array_map ('safeXSS', $search);
}
search form input:
<input type="submit" name="search" class="submit" value="search" />
I do not understand what's my problem?! how do i can fix this?
In your PHP template somewhere you will have code like:
<a href="<?php echo $uri ?>">
or:
echo "<a href=\"$uri\">";
HTML-escaping is missing here, so if a quote character is included in the value in $uri then that URI content escapes the attribute value it is supposed to be contained in, and you get dangerous output:
<a href=""onmouseover='prompt(961413)'bad=">">
You should fix this by calling htmlspecalchars() each and every time you output a plain text string into HTML text content or attribute values:
<a href="<?php echo htmlspecialchars($uri, ENT_QUOTES 'utf-8') ?>">
(You can make this less obtrusive by defining a short-named function like h() that calls echo htmlspecialchars for you. Or, in the longer term, prefer to use a template language that does this automatically for you.)
The filtering you've got on $_POST/$_GET is not at all effective. It is unclear what safeXSS is doing exactly, and I have absolutely no idea what rawurldecode is there for, but in general it is not possible to implement correct handling of string escaping at the input stage.
Using input ‘sanitisation’ to attempt to combat XSS is a common antipattern that should be avoided. (You may want to do custom input filtering for other reasons, but it's the wrong way to handle injection/escaping problems.) HTML-injection, JavaScript-injection, XML-injection and so on are output-stage concerns; the input stage doesn't know what contexts input is going to be used in yet, so can't treat the input in the correct way for that output context.
I just started helping on a site where there is an admin section that allows the site owner to input text to display on the site. They have a problem when adding text with apostrophes because it breaks the PHP statement. I have looked at using mysql_real_escape_string command, but not sure the best way to use it. The original code is below. Any suggestions would be great!
<textarea name="descr" cols="76" rows="5" id="descr" tabindex="5" onBlur="this.value=removeMSWordChars(this.value);">
<?php echo $data['descr']; ?>
</textarea>
<script type="text/javascript">
CKEDITOR.replace( 'descr' );
</script>
</td>
Read about Prepared Statements, they allow you to:
Make you code safe against SQL injection attacks
Insert any character easily into the database, without caring about escaping.
You seem to be still using the MySQL-extension (the one with mysql_query): Note that this extension is deprecated and does not support Prepared Statements. You should switch to either PDO or MySQLi, the link at the top explains how to.
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
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.