I wanted to pass PHP variables to Javascript without triggering any new http request (aka: inserting it directly in markup). But I wanted the content as is (without any sanitization that could change my values, even if they where markup itself). Of course I wanted to keep it safe as well.
The best way i've came up so far includes json + base64_encode + data uri schemes:
<script type="text/javascript" src="data:text/javascript;base64,<?php echo base64_encode('var thing = '.json_encode($thing)); ?>"></script>
My question is: will this have any side effect? can I safely use this?
I certainly wouldn't do this. You're introducing unnecessary compatibility problems (IE). By base64 encoding, you're bloating the size of your JSON by ~37%.
<script type="text/javascript">var thing = <?php echo json_encode($thing); ?></script>
Realistically, the only problem you might run in to is if $thing has a '</script>' in a string somewhere. (It looks like json_encode() actually escapes all forward slashes /, so this isn't a problem.) HTML parsers will ignore anything else that might look like markup in a <script> block.
You do have to watch out for text encoding if your page isn't UTF-8.
Related
Okay I've something looks like below from user input, known that a </script> will not working inside a document.write() function
<script type="text/javascript">document.write("<script type='text/javascript' src='"+(location.protocol == 'https:' ? 'https:' : 'http:') + "//www.domain.com/script.js'></script>");</script>
Is there anyway to replace the </script> to </scr"+"ipt> inside document.write() function?
Is there anyway to replace the </script> to </scr"+"ipt> inside document.write() function?
No.
The sequence of characters </script> is parsed as an end tag by the HTML parser before it even reaches the JavaScript parser.
You have to edit the source code before sending it to the browser.
That said, there are better ways to approach the problem then looking a location.protocol anyway. Use a scheme relative URI instead:
<script src="//www.example.com/script.js'></script>
Or redirect all HTTP traffic for the HTML document to HTTPS so that you never serve it on an insecure connection.
Your comments suggest that the question you should have asked was:
How can I place arbitrary submitted form data into a JavaScript string literal using PHP?
Use the json_encode function. If you pass it a string, it will give you a JavaScript escaped string suitable for inserting into a <script> element. (It won't be a valid JSON Text though, since that must have an object or array at the outermost level).
<script>
document.write(<?php echo json_encode($_POST['script']); ?>);
</script>
Serious security warning: Do not do this without implementing protection from CSRF attacks as allowing third parties to cause your users to submit JavaScript to your site could be a major problem.
Questions:
What are the best safe1(), safe2(), safe3(), and safe4() functions to avoid XSS for UTF8 encoded pages? Is it also safe in all browsers (specifically IE6)?
<body><?php echo safe1($xss)?></body>
<body id="<?php echo safe2($xss)?>"></body>
<script type="text/javascript">
var a = "<?php echo safe3($xss)?>";
</script>
<style type="text/css">
.myclass {width:<?php echo safe4($xss)?>}
</style>
.
Many people say the absolute best that can be done is:
// safe1 & safe2
$s = htmlentities($s, ENT_QUOTES, "UTF-8");
// But how would you compare the above to:
// https://github.com/shadowhand/purifier
// OR http://kohanaframework.org/3.0/guide/api/Security#xss_clean
// OR is there an even better if not perfect solution?
.
// safe3
$s = mb_convert_encoding($s, "UTF-8", "UTF-8");
$s = htmlentities($s, ENT_QUOTES, "UTF-8");
// How would you compare this to using using mysql_real_escape_string($s)?
// (Yes, I know this is a DB function)
// Some other people also recommend calling json_encode() before passing to htmlentities
// What's the best solution?
.
There are a hell of a lot of posts about PHP and XSS.
Most just say "use HTMLPurifier" or "use htmlspecialchars", or are wrong.
Others say use OWASP -- but it is EXTREMELY slow.
Some of the good posts I came across are listed below:
Do htmlspecialchars and mysql_real_escape_string keep my PHP code safe from injection?
XSS Me Warnings - real XSS issues?
CodeIgniter - why use xss_clean
safe2() is clearly htmlspecialchars()
In place of safe1() you should really be using HTMLPurifier to sanitize complete blobs of HTML. It strips unwanted attributes, tags and in particular anything javascriptish. Yes, it's slow, but it covers all the small edge cases (even for older IE versions) which allow for safe HTML user snippet reuse. But check out http://htmlpurifier.org/comparison for alternatives. -- If you really only want to display raw user text there (no filtered html), then htmlspecialchars(strip_tags($src)) would actually work fine.
safe3() screams regular expression. Here you can really only apply a whitelist to whatever you actually want:
var a = "<?php echo preg_replace('/[^-\w\d .,]/', "", $xss)?>";
You can of course use json_encode here to get a perfectly valid JS syntax and variable. But then you've just delayed the exploitability of that string into your JS code, where you then have to babysit it.
Is it also safe in all browsers (specifically IE6)?
If you specify the charset explicitly, then IE won't do its awful content detection magic, so UTF7 exploits can be ignored.
http://php.net/htmlentities note the section on the optional third parameter that takes a character encoding. You should use this instead of mv_convert_encoding. So long as the php file itself is saved with a utf8 encoding that should work.
htmlentities($s, ENT_COMPAT, 'UTF-8');
As for injecting the variable directly into javascript, you might consider putting the content into a hidden html element somewhere else in the page instead and pulling the content out of the dom when you need it.
The purifiers that you mention are used when you want to actually display html that a user submitted (as in, allow the browser to actually render). Using htmlentities will encode everything such that the characters will be displayed in the ui, but none of the actual code will be interpreted by the browser. Which are you aiming to do?
Due to the nature of my project. I am pulling data from my db and outputting to javascript. Things were working just fine till I got to the main content. It has strings like (;, :, - ''). How do I ensure that these are displayed without crushing my script coz as for now nothing seems to work.
If all you have is a single string value then see answer by Tomalak Geret'kal.
If there is any chance of getting something more than a single value from your database, like an array, object, null, or anything more complex, then I would suggest using json_encode. By using something like this:
<script>
var your_JavaScript_variable = <?php echo json_encode(your_PHP_variable); ?>;
</script>
you can pass complex data structures, arrays, or even single strings from PHP to JavaScript with all of your backslash escaping done automatically.
Additionally when you use JSON for moving your data from PHP to JavaScript it will be easy to make your application get the data from your server asynchronously without page refreshes using AJAX in the future.
You can use the PHP addslashes function for inserting into Javascript, and htmlspecialchars for inserting into HTML.
You should be encoding that data into json. PHP has a handy function to do this, json_encode.
Be sure to use the JSON_HEX_QUOTE option or the quotes in your data will break your js.
Read this: http://php.net/manual/en/function.json-encode.php
I am trying to pass a php variable inside javascript bt it is not working.
Comment
Is it possible to do so or I may be incorrect somewhere...
Thanks for your response in advance! :)
First of all, you probably should change 'java' tag to 'javascript'.
Regarding your question - PHP is parsed on the server side, while Javascript runs on the client side. If you are not going to use AJAX and asynchronous calls, you could write values to the JS source, like this:
<script type="text/javascript">
var foo = <?php echo $yourData; ?>;
alert(foo);
</script>
Comment
You're dynamically generating Javascript. You will save yourself some headaches if when you need to do this you, keep it simple. Transfer the data from PHP to Javascript in the simplest way possible at the top of the page:
<script type="text/javascript" >
var $current = '<%? echo $current; %>';
</script>
As others have pointed out, you will want to encode and quote your php variable, using json_encode (in which case you probably won't need the quotes), or a simpler escape function if you know the possible values.
Now, your inline code can be simpler:
Comment
A final recommendation would be to pull this out into its own function, and use the "onclick" attribute.
Use json_encode() if your PHP has it.
This will automatically quote and escape your string and ensures that special characters are properly encoded to prevent cross-site scripting (XSS) attacks.
However, I think you will have to pass UTF-8 strings to this function.
And vol7ron has a good point – you should put a semicolon ; after your statement and put a space between that and the question mark ? for better legibility.
Comment
You can also pass booleans, ints and even entire arrays to json_encode() to pass them to JavaScript.
I know, I know - obfuscated html/js code is useless (I read the other questions on SO), but I still want to make life harder for copy-cats of my site...
I'm running a php based website, which generates html output. I would like the FINAL html output (which has html, js, json and uses ajax) to be obfuscated. Is there a php function for that purpose? I found http://www.ioncube.com/html_encoder.php but that relies on some of their special software to be loaded on the server - ie, a no-go...
Any suggestions?
Not true obfuscation, but rather hard to read in most cases (and less bandwidth-intensive as well!)
<?php
ob_start();
// Generate output here
$output = ob_get_contents();
ob_end_clean();
$output = preg_replace('\s{2,}',' ', $output);
echo $output;
?>
You can compress your JavaScript and css
For php output it can be done using ob_start have a look at this http://ru.php.net/manual/en/function.ob-start.php#71953
You should have a look at Minify it has a Minify_HTML class removing whitespace, unnecessary comments and tokens
Well, in my studies of HTML obfuscator, like http://htmlobfuscator.com/, are truely change their "special" code into reversed base64.
When we decode it, they're actually packed js file using packer that you could find on Google.
So, now we could do this
Slashup the whole html, for the Js string, then "pack" the javascript, then encode it into base64, then rotate the encoded string. Viola, done.
You'll get something like this:
var IO1='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';function l1O(data){var OOOlOI="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var o1,o2,o3,h1,h2,h3,h4,bits,i=0,enc='';do{h1=OOOlOI.indexOf(data.charAt(i++));h2=OOOlOI.indexOf(data.charAt(i++));h3=OOOlOI.indexOf(data.charAt(i++));h4=OOOlOI.indexOf(data.charAt(i++));bits=h1>16&0xff;o2=bits>>8&0xff;o3=bits&0xff;if(h3==64){enc+=String.fromCharCode(o1)}else if(h4==64){enc+=String.fromCharCode(o1,o2)}else{enc+=String.fromCharCode(o1,o2,o3)}}while(i= 0; i-- ){ ret += string.charAt(i);} return ret; }eval(l1O(OOO(IO1)));
Good luck~
No, php couldn't do that without something on the client side. You could always have some javascript decode it, but that wouldnt be friendly to whoever has it turned off, it would be slow and no search engine support.