开发者

Broad overview, flowchart on escaping user submitted content for html, javascript, and PHP

can anyone point me to good StackOverflow answers and other resources, including books, on escaping user submitted content for HTML, JavaScript, and PHP?

For example, say a user types information in a text box, and clicks a submit button. Then the text is written by JavaScript into a div on the page, and is also sent via GET to PHP, and by PHP is put into a MySQL database.

I am looking for a good, broad, but also detailed overview all the different types of escaping involved. A flowchart would help too!

Thanks!


Thanks! I'm looki开发者_如何学编程ng for someone to make like a cheatsheet, with sections on 1) escaping for html display, 2) escaping for putting in a URL 3), sending the URL to PHP, 4) inserting data from the URL into a database. Each section should have 1) examples on potential problematic situations and characters that should be escaped, 2) examples on how to escape the characters, and 3) how to decode the characters if necessary later.

The benefit would be a one-stop source with many examples and solutions on escaping so that other users don't have to go through tons of different sites and answers and resources which have few examples and solutions. I think it would be great.


This chart looks pretty good so far http://www.the-art-of-web.com/javascript/escape/


I'd always use "POST" for user data myself, not "GET", and the following discussion reflects that, but you'll still be able to use about 90% of what I say below either way. So here goes...

General rule: Don't "think ahead" when escaping data. Only make the immediately necessary transformation. Canonical example: Don't escape for HTML when doing a database insertion, since you'll end up with, for example, '&' turning into '&' after a couple of round trips.

General rule: Use UTF-8 throughout. You'll be thankful for this the first time someone does a copy-paste from an email that has a unicode ellipsis in it. (You'd be surprised how often that happens.) Typical settings needed; this may vary with PHP/MySQL/HTML version:

  • PHP: php_value default_charset "UTF-8"
  • MySQL: Choose utf8 when creating the database.
  • HTML: <meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>

General rule: There are only five places that unsanitized (though properly escaped) user data can go:

  • The value of a (properly-typed) database field (i.e. a UTF-8 text field or blob field).
  • The value of a PHP variable.
  • The value of a Javascript variable.
  • The value of an HTML form element's 'value' attribute.
  • The content of an HTML element's textNode child.

If you want to put user data in any other place, it must be sanitized. This is beyond the scope of the question, but in a typical case you might use a regular expression to replace anything that isn't an ASCII letter or number with an underscore. In cases where uniqueness matters, like a filename or an HTML 'id' attribute, additional work has to be done to make sure that the sanitized names are unique (e.g. make sure that the clash that happens when'a^b' and 'a&b' are both sanitized to 'a_b' is resolved). A typical solution looks something like:

filename = original_filename;
while(already_exists(filename)) {count++; filename = original_filename + count;}

And, finally, the meat of my response: The specific escape functions to use to move data to and from those Five Special Places where unmodified user data can go:

  • HTML form value attribute -> PHP $_POST variable: No escaping necessary.
  • PHP variable -> database field: PDO prepared statement:

    $stmt = $db->prepare('insert into roundtrip (id, name) values (NULL, :data)');
    $stmt->execute(array('data' => $_POST['name']));
    
  • Database field -> PHP variable: No escaping necessary, but use PDO prepared statement to escape query values:

    $stmt = $db->prepare('select id, name from roundtrip where name = :data');
    $stmt->execute(array('data' => $_POST['name']));  // User data needs escaping.
    while ($result = $stmt->fetch()) {
        echo $result['name']; // DB result doesn't.
    }
    
  • PHP variable -> Javascript variable: json_encode:

    var data = <?php echo json_encode(data); ?>;
    
  • PHP variable -> HTML textNode or form value: htmlspecialchars:

    <div><?php echo htmlspecialchars(data); ?></div>
    <input type="text" name="name" value="<?php echo htmlspecialchars(data); ?>"/>
    
  • Javascript <-> HTML textNode or form value: Browser's built-in textNode and .value attributes/functions:

    data = source_div.textContent; // Firefox
    data = source_div.innerText; // Other browsers
    target_div.textContent = data; // Firefox
    target_div.innerText = data; // Other browsers
    
    // To/from form element.
    data = source_form.value;
    target_form.value = data;
    
    // Append to element.
    target_div.appendChild(document.createTextNode(data)); // All browsers
    
    // jQuery textNode
    data = $('#source_div_id').text();
    $('#target_div_id').text(data);
    
    // jQuery form value
    data = $('#source_form_id').val();
    $('#target_form_id').val(data);
    

Do a repeated round-trip test with a string like this to make sure it always goes through the whole HTML->PHP->DB->PHP->[Javascript->]HTML cycle exactly the same every time:

&amp;ДЖäüöéè<script>…</script>™<i>bold</i>

Here's my script that tests escaping every which way; it obviously needs a database, a table with name 'roundtrip' and columns 'id' and 'name', and single row with id=1 to be created before running it:

<?php
$db = new PDO("mysql:host=$host;dbname=$dbname", $db_user, $db_password);
$stmt_insert = $db->prepare('
update
    roundtrip
set
    name = :name
where
    id = 1
');
$stmt_select = $db->prepare('
select
    name
from
    roundtrip
where
    id = 1
');
if ($_POST['do'] == 'edit') {
    $stmt_insert->execute(array('name' => $_POST['name']));
}
$stmt_select->execute();
while ($result = $stmt_select->fetch()) {
    $data = $result['name'];
}
?>
<!DOCTYPE html>
<html>
<head>
    <title>Roundtrip test</title>
    <script type="text/javascript" src="/js/jquery-1.7.1.min.js"></script>
    <script type="text/javascript">
        function copydiv() {
            // Non-jquery:
            //var source = document.getElementById('divdata');
            //var target = document.getElementById('copydiv');
            //if (typeof(source.textContent) != "undefined") {
            //    target.textContent = source.textContent;
            //} else {
            //    target.innerText = source.innerText;
            //}

            // jquery:
            $('#copydiv').text($('#divdata').text());
        }
        function copyform() {
            // Non-jquery:
            //var source = document.getElementById('formdata');
            //var target1 = document.getElementById('copyform1');
            //var target2 = document.getElementById('copyform2');
            //if (typeof(source.textContent) != "undefined") {
            //    target1.textContent = source.value;
            //} else {
            //    target1.innerText = source.value;
            //}
            //target2.value = source.value;

            // jquery:
            $('#copyform1').text($('#formdata').val());
            $('#copyform2').val($('#formdata').val());
        }
        function copyjson() {

            var data = <?php echo json_encode($data); ?>;

            // Non-jquery:
            //var target = document.getElementById('copyjson');
            //if (typeof(target.textContent) != "undefined") {
            //    target.textContent = data;
            //} else {
            //    target.innerText = data;
            //}

            // jquery:
            $('#copyjson').text(data);
        }
    </script>
</head>
<body>
    <div>Data: <span id="divdata"><?php echo htmlspecialchars($data); ?></span></div>
    <div>JS div copy: <span id="copydiv"/></div>
    <div>JS form copy: <span id="copyform1"/></div>
    <div>JSON copy: <span id="copyjson"/></div>
    <form method="POST">
        <input type="hidden" name="do" value="edit"/>
        <input type="text" name="name" id="formdata" value="<?php echo htmlspecialchars($data); ?>"/>
        <input type="text" id="copyform2"/>
        <input type="button" value="Copy div" onclick="copydiv();"/>
        <input type="button" value="Copy form" onclick="copyform();"/>
        <input type="button" value="Copy json" onclick="copyjson();"/>
        <input type="submit"/>
    </form>
</body>
</html>


To insert escaped things in a MySQL-Database using PHP (and other programming languages), there are the PreparedStatements.

If you want to directly display the users input in a div box and escape the input (so that HTML-Tags aren't interpreted i guess), you can check Point #4 in this article or use Google.


OWASP has an XSS Prevention Cheat Sheet which covers most (all?) of what you seem to be looking for. Does not address PHP directly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜