1

我正在开发一个方向服务,用户输入从地址和到地址并获取方向表(提供转弯信息)以及显示路线的地图。

下面是完整的源代码(getdirections.php):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
 <title>Directions</title>
 <style>
  * { 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; }
 </style>
 <script src="jquery-1.3.1.js" type="text/javascript">
 </script>
 <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false& amp;key=[Your Key Here]" 
type="text/javascript">
 </script>
</head>
<body onunload="GUnload()">
<div id="container">    
<div id="directform">
    <form id="direct" action="getdirections.php" method="get">
<p><label for="loc1">From Here:</label>
<input id="loc1" type="text" name="location1" class="required" /></p>
<p><label for="loc2">To Here:</label>
<input id="loc2" type="text" name="location2" class="required" /></p>
<p><input type="submit" value="Search" /></p>
    </form>
</div>
<?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 => $value ) {
     $ch = '';
     if ( $value[strlen($value)-1] == ',') {
    $ch = ',';
    $value = substr($value, 0, -1);
     }

$value = 
      preg_replace('/^(\&|\(|\)|\[|\]|\{|\}|\"|\.|\!|\?|\'|\:|\;)+/', "", $value);

$inputarray[$i] = 
      preg_replace('/(\&|\(|\)|\[|\]|\{|\}|\"|\.|\!|\?|\'|\:|\;)+$/', "", $value);
$inputarray[$i] = $inputarray[$i].$ch;
}
$filteredString = implode(" ", $inputarray);
return $filteredString;
}

?>
</div>    
<table class="directions">
 <tr>
 <td valign="top">
  <div id="directions" style="width: 100%"></div>
 </td>
</tr>
<tr>
 <td valign="top">
 <div id="map_canvas" style="width: 250px; height: 400px"></div>
 </td>
</tr>
<td valign="top">
 <div id="directions_url"></div>
</td>   
</table>

 <noscript><b>JavaScript must be enabled in order for you to use Google Maps.</b> 
  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.
 </noscript>
 <script type="text/javascript">

 // 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 = "<?= filterInput($_GET['location1']) ?>" || 0;
        location2 = "<?= filterInput($_GET['location2']) ?>" || 0;
        var directions = document.getElementById(directionsid);
        directions.innerHTML = "Please check the address and try again";

        if ( GBrowserIsCompatible() && location1 != 0  && 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 += "&daddr=";
    url += location2;
    var a = $("<a></a>").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);
</script>
</body>
</html>

如果您在系统名称上试用此代码,则将其命名为 getdirections.php。您唯一需要更改的是 google maps api 密钥。你可以在这里拿到钥匙。

生成密钥后,将密钥放入密钥参数中(为方便起见,复制了下面的行):

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false& amp;key=[Your key here]" 
type="text/javascript">

从上面的代码可以看出,我通过 PHP 获取输入并在 Javascript 中进行处理。现在,我不希望用户摆脱任何类型的输入(javscript、危险的 HTML 等)。我尝试在 PHP 中使用 urlencode 函数。但是,javascript 代码不接受编码的用户输入,即使输入良好也会失败。

作为这个问题的解决方法,我在 PHP 中编写了一个 filterInput 函数,它将替换/删除某些字符并阻止用户尝试通过输入执行 Javascript 代码的任何尝试。

这运作良好。但是,当用户确实尝试提供恶意输入时,例如 "+alert("hello")+" 包含开头和结尾的引号,filterInput 函数会修剪前导引号和尾引号,结果字符串如下:

+alert("hello")+

现在当执行下面的代码时:

location1 = "<?= filterInput($_GET['location1']) ?>" || 0;

PHP 用它的返回值替换函数调用,如下所示:

location1 = "+alert("hello")+" || 0;

脚本的执行因上面的行而停止并出现错误(缺少;之前的语句)

请注意,如果我没有修剪引号并直接使用 $_GET['location1'] 我会得到。

location1 = ""+alert("hello")+"" || 0;

alert("hello") 会被执行!!

所以,我正在修复中。如果我过滤输入,我会在某些用户输入上得到一个 javascript 错误,如果我不过滤输入,我允许用户执行任何类型的 javascript。

那么我的问题是:

  • 什么是处理网络输入的正确且安全的方法?
  • 这种跨语言(从 PHP 到 Javascript)的用户输入可以吗?
  • 除了用户能够执行 javascript 之外,还有哪些其他类型的安全威胁,这段代码是否容易受到攻击?

谢谢阅读!!

请帮忙。

4

1 回答 1

2

您可以在 php 中尝试 json_encode,在 javascript 中尝试 eval。

如果 JS 在完成输入的同一台机器上执行,我不会太担心安全性。黑客可以破解自己的机器,应该没问题。

于 2009-07-08T18:32:55.093 回答