Search code examples
phpmysqlpdoxsssql-injection

How to prevent XSS attack (php/pdo)


I have functions, first: JS:

    $(document).ready(function() {

        //dodavanje novog racuna
       $(function() { 
        $('#addFieldForm').submit(function(e) { 
            e.preventDefault();

            if ( $(this).parsley('validate') ) {

            $.ajax({
                url: "insertRacun.php",
                type: "POST",
                async: true, 
                data: { sifra:sifra,brojracuna:$("#brojracuna").val(),sufiks:$("#sufiks").val(),kupac:$("#kupac").val(),adresa:$("#adresa").val(),grad:$("#grad").val(),pib:$("#pib").val(),total:$("#total").text(),valuta:$("#valuta").val(),nacin:$("#nacin").val(),datum:$("#datum").val(),rok:$("#rok").val(),isporuka:$("#isporuka").val(),napomena:$("#napomena").val(),interna:$("#interna").val(),ponovi:$("#ponovi").val()},           
                dataType: "html",
etc...

php:

try {        
                $STH = $db->prepare("INSERT INTO racuni (br, sufiks, kupac, adresa, grad, pib, total,valuta,nacin,datum,rok,isporuka,napomene,interne, user_id,sifra) VALUES (:0,:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15)");
                $STH->bindParam(':0', $_POST['brojracuna']);
                $sufiks=$_POST['sufiks'];
                $STH->bindParam(':1', $sufiks);
        $STH->bindParam(':2', $_POST['kupac']);
                $STH->bindParam(':3', $_POST['adresa']);
etc....

and when I try to add:

Luciansdasadsda"><script>alert(1)</script>

then I get in database the same value.

So How I can prevent XSS and SQL injection in my code? ALso how to prevent Denial of service (causing excessive amounts of rows to be created)?


Solution

  • OWASP Cross Site Scripting (XSS) Prevention Cheat Sheet
    https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet


    The string value you're passing in to the database is being stored in the database. That's the expected behavior. Nothing in the MySQL, PDO, or prepared statements with bind placeholders is designed to prevent a string that looks like javascript from being stored.

    That's all designed to prevent malicious strings from being interpreted as part of a SQL statement, ala XKCD Exploits of a Mom https://xkcd.com/327/

      Robert'; DROP TABLE students; --
    

    So, you're handling "Little Bobby Tables" just fine.

    You're asking about handling Bobby's cousin: "Shifty Earl".

      <script>alert('hello')</script>
    

    We can get Shifty Earl's name inserted into the table just fine; there's no malicious SQL Injection to be thwarted.

    The problem comes when we go to put "Shifty Earl"'s name back out on a web page.

    We have to treat his name as being potentially unsafe (just like we did with Little Bobby Tables).

    Here, it's unsafe to put it on a web page, unless we properly escape it.

    So, how do we escape that to make it safe for display?

    PHP has a nifty function called htmlentities. (Other languages/libraries have equivalent functions.)

    The return from:

     htmlentities("<script>alert('hello')</script>") 
    

    will be something like this:

     &lt;script&gt;alert('hello')&lt;/script&gt;
    

    Note that "&lt;" is called an html entity. It represents a "less than" character, but it will not be interpreted as the beginning of a tag. We'd get an equivalent result with "&#60;".

    When we put that escaped/encoded string out on a web page, what the browser displays looks like the original string...

     <script>alert('hello')</script>
    

    But, this is not and will not be interpreted as HTML tags.

    How do you prevent XSS vulnerabilities?

    By properly escaping all potentially unsafe values (by replacing HTML tag characters with an equivalent html entity) when those values are incorporated into a web page (at the time the web page is being prepared to be sent to the client.)

    The database really has nothing to do with it.

    The reason we don't do the "htmlentities" escaping when we store string in the database is that it's not the right place to do it.

    Someone looking at your code is going to see that a potentially unsafe value is being put onto the web page, and will add the appropriate htmlentities function there, either right before it's put to the page. And then we'd get double escaping, encoding the values a second time.

    The right place to do the escaping is right when the value is put on the web page.

    There are other sources of potentially unsafe values, values read in from a file, from some other table, or values supplied by the user on a web form. It would wonky for the code to assume that values from one particular column in one particular table is "safe", and that values from other sources aren't safe.


    OWASP SQL Injection
    https://www.owasp.org/index.php/SQL_Injection

    OWASP Cross Site Scripting (XSS) Prevention Cheat Sheet
    https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet