Note that there are some explanatory texts on larger screens.

plurals
  1. POUser input, PHP, Javascript and security
    text
    copied!<p>I am working on a directions service where users enter the from and to addresses and get the directions table ( that gives turn by turn information ) along with a map showing the route.</p> <p>Below is the complete source code ( getdirections.php ):</p> <pre><code>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; &lt;head&gt; &lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /&gt; &lt;title&gt;Directions&lt;/title&gt; &lt;style&gt; * { font-family: Verdana; font-size: 96%; } label { width: 15em; float: left; } label.error { display: block; float: none; color: red; vertical-align: top; } p { clear: both; } .submit { margin-left: 12em; } em { font-weight: bold; padding-right: 1em; vertical-align: top; } &lt;/style&gt; &lt;script src="jquery-1.3.1.js" type="text/javascript"&gt; &lt;/script&gt; &lt;script src="http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;sensor=false&amp; amp;key=[Your Key Here]" type="text/javascript"&gt; &lt;/script&gt; &lt;/head&gt; &lt;body onunload="GUnload()"&gt; &lt;div id="container"&gt; &lt;div id="directform"&gt; &lt;form id="direct" action="getdirections.php" method="get"&gt; &lt;p&gt;&lt;label for="loc1"&gt;From Here:&lt;/label&gt; &lt;input id="loc1" type="text" name="location1" class="required" /&gt;&lt;/p&gt; &lt;p&gt;&lt;label for="loc2"&gt;To Here:&lt;/label&gt; &lt;input id="loc2" type="text" name="location2" class="required" /&gt;&lt;/p&gt; &lt;p&gt;&lt;input type="submit" value="Search" /&gt;&lt;/p&gt; &lt;/form&gt; &lt;/div&gt; &lt;?php function filterInput ( $input ) { $replacement = ','; $input = preg_replace('/(\n|\r)+/', $replacement, $input); $replacement = " "; $input = preg_replace('/(\t)+/', $replacement, $input); $inputarray = explode(' ', $input); foreach ( $inputarray as $i =&gt; $value ) { $ch = ''; if ( $value[strlen($value)-1] == ',') { $ch = ','; $value = substr($value, 0, -1); } $value = preg_replace('/^(\&amp;|\(|\)|\[|\]|\{|\}|\"|\.|\!|\?|\'|\:|\;)+/', "", $value); $inputarray[$i] = preg_replace('/(\&amp;|\(|\)|\[|\]|\{|\}|\"|\.|\!|\?|\'|\:|\;)+$/', "", $value); $inputarray[$i] = $inputarray[$i].$ch; } $filteredString = implode(" ", $inputarray); return $filteredString; } ?&gt; &lt;/div&gt; &lt;table class="directions"&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;div id="directions" style="width: 100%"&gt;&lt;/div&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;div id="map_canvas" style="width: 250px; height: 400px"&gt;&lt;/div&gt; &lt;/td&gt; &lt;/tr&gt; &lt;td valign="top"&gt; &lt;div id="directions_url"&gt;&lt;/div&gt; &lt;/td&gt; &lt;/table&gt; &lt;noscript&gt;&lt;b&gt;JavaScript must be enabled in order for you to use Google Maps.&lt;/b&gt; However, it seems JavaScript is either disabled or not supported by your browser. To view Google Maps, enable JavaScript by changing your browser options, and then try again. &lt;/noscript&gt; &lt;script type="text/javascript"&gt; // This programming pattern limits the number of global variables // Thus it does not pollute the global namespace // for_directions is the only global object here. for_directions = function(){ // The map is loaded into the div element having id specified by mapid // private variable var mapid = "map_canvas"; // The direction listing is loaded into the div element having id specified by directionsid. // private variable var directionsid = "directions"; // From here // private variable var location1; // To here // private variable var location2; // The functions ( init and addevent ) are public methods of for_directions object return { // Called on loading of this page // public method init: function (){ location1 = "&lt;?= filterInput($_GET['location1']) ?&gt;" || 0; location2 = "&lt;?= filterInput($_GET['location2']) ?&gt;" || 0; var directions = document.getElementById(directionsid); directions.innerHTML = "Please check the address and try again"; if ( GBrowserIsCompatible() &amp;&amp; location1 != 0 &amp;&amp; location2 != 0){ mapAddress(location1, location2); } }, // This method is cross browser compliant and is used to add an event listener // public method addEvent:function(elm,evType,fn,useCapture){ if(elm.addEventListener){ elm.addEventListener(evType, fn, useCapture); return true; } else if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r; } else { elm['on' + evType] = fn; } } }; // Called from init // private method function mapAddress ( address1, address2 ){ var geocoder = new GClientGeocoder(); var directions = document.getElementById(directionsid); var i = 0; geocoder.getLatLng( address1, function(point1){ if (point1){ geocoder.getLatLng ( address2, function(point2){ if (point2){ getDirections(); } else { directions.innerHTML = "Please check the address and try again"; } }); } else { directions.innerHTML = "Please check the address and try again"; } }); } // Called from mapAddress to load the directions and map // private method function getDirections( ){ var gmap = new GMap2(document.getElementById(mapid)); var gdir = new GDirections(gmap,document.getElementById(directionsid)); gdir.load("from: " + location1 + " to: " + location2, { "locale": "en_US" }); generateURL(); } function generateURL(){ var url = "http://maps.google.com/maps?saddr="; url += location1; url += "&amp;daddr="; url += location2; var a = $("&lt;a&gt;&lt;/a&gt;").attr('href',url); $(a).text("Google Maps"); $("#directions_url").append(a); } }(); // The (); above results in the function being interpreted by the browser just before the page is loaded. // Make for_directions.init as the listener to load event // Note that the init method is public that why its accessible outside the object scope for_directions.addEvent(window, 'load', for_directions.init, false); &lt;/script&gt; &lt;/body&gt; &lt;/html&gt; </code></pre> <p>If you try out this code on your system name it as getdirections.php. The only thing you would need to change is the google maps api key. You can get the key <a href="http://code.google.com/apis/maps/signup.html" rel="nofollow noreferrer">here</a>.</p> <p>Once you generate your key put in the key parameter ( reproduced the line below for convenience ):</p> <pre><code>&lt;script src="http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;sensor=false&amp; amp;key=[Your key here]" type="text/javascript"&gt; </code></pre> <p>As is seen from the code above, I get the input through PHP and do the processing in Javascript. Now, I don't want users to get away with any kind of input ( javscript, dangerous HTML, etc ). I tried using the urlencode function in PHP. However, the encoded user input is not accepted by the javascript code and fails even on good input.</p> <p>As a workaround to this problem I wrote a filterInput function in PHP that will replace/delete certain characters and thwart any attempt by the user to try and execute Javascript code through input. </p> <p>This worked well. However, when the user did try give malicious input, say like "+alert("hello")+" with both the beginning and ending quotes included, the filterInput function trimmed the leading and tailing quotes and the resulting string is below:</p> <pre><code>+alert("hello")+ </code></pre> <p>Now when code below is executed:</p> <pre><code>location1 = "&lt;?= filterInput($_GET['location1']) ?&gt;" || 0; </code></pre> <p>PHP substitues the function call with its return value like below:</p> <pre><code>location1 = "+alert("hello")+" || 0; </code></pre> <p>Execution of the script halts with the line above with an error ( missing ; before statement )</p> <p>Note, had I not trimmed the quotes and used $_GET['location1'] directly I would get.</p> <pre><code>location1 = ""+alert("hello")+"" || 0; </code></pre> <p>alert("hello") would get executed!!</p> <p>So, I am in a fix. If I filter input I get a javascript error on certain user input and if I don't filter input I allow users to execute any kind of javascript. </p> <p>My questions then are:</p> <ul> <li>What is a proper and secure way to handle input on the web?</li> <li>Is this kind of user input crossing languages ( from PHP to Javascript ) ok?</li> <li>Apart from the user being able to execute javascript what other kinds of security threats does is this piece of code vulnerable?</li> </ul> <p>Thanks for reading!! </p> <p>Please help.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload