如何在您的网页上安全地输出用户提交的链接?

How To Output User Submitted Links On Your Webpage Securely?

我想允许我的网站访问者(任何 Tom、Dick 和 Harry)将他们的链接提交到我的网页以在我的页面上输出。 在我的页面上回显他们提交的 url 之前,我需要解析用户提交的 url。需要解析网址,因为我不知道他们将提交什么网址,也不知道他们网址的结构。

用户理论上可以访问我的页面并注入一些 Javascript 代码,例如:

?search=<script>alert('hacked')</script>

你明白我的意思。

我必须编写 php 脚本,当用户提交他们的 url 时,我的 php 脚本会解析他们的 url 并通过在输出之前在适当的位置添加 urlencode、rawurlencode、intval 对它们进行编码通过 htmlspecialchars。 另一个写了下面的脚本。问题是,它输出如下:

http%3A%2F%2Fexample.com%2Fcat%2Fsubcat?var_1=value+1&var2=2&this_other=thing&number_is= 13

它应该像这样输出:

http://example.com/cat/subcat?var_1=value+1&var2=2&this_other=thing&number_is=13

这是他们的代码.... 第三方代码:

<?php
function encodedUrl($url){
    $query_strings_array = [];
    $query_string_parts  = [];
    // parse URL & get query
    $scheme        = parse_url($url, PHP_URL_SCHEME);
    $host          = parse_url($url, PHP_URL_HOST);
    $path          = parse_url($url, PHP_URL_PATH);
    $query_strings = parse_url($url, PHP_URL_QUERY);

    // parse query into array
    parse_str($query_strings, $query_strings_array);

    // separate keys & values
   $query_strings_keys   = array_keys($query_strings_array);
   $query_strings_values = array_values($query_strings_array);

   // loop query
  for($i = 0; $i < count($query_strings_array); $i++){
       $k   = urlencode($query_strings_keys[$i]);
       $v   = $query_strings_values[$i];
       $val = is_numeric($v) ? intval($v) : urlencode($v);
    
       $query_string_parts[] = "{$k}={$val}";
   }

   // re-assemble URL
   $encodedHostPath = rawurlencode("{$scheme}://{$host}{$path}");

   return $encodedHostPath . '?' . implode('&', $query_string_parts);
}

$url1 = 'http://example.com/cat/subcat?var 1=value 1&var2=2&this other=thing&number is=13';
$url2 = 'http://example.com/autos/cars/list.php?state=california&max_price=50000';

// run urls thru function & echo
// run urls thru function & echo
echo $encoded_url1 = encodedUrl($url1); echo '<br>'; 
echo $encoded_url2 = encodedUrl($url2); echo '<br>'; 
?>

所以,我改变了他们的:

$encodedHostPath = rawurlencode("{$scheme}://{$host}{$path}");

我的这个(我的修改):

$encodedHostPath = rawurlencode("{$scheme}").'://'.rawurlencode("{$host}").$path;

它似乎在起作用。输出时:

http://example.com/cat/subcat?var_1=value+1&var2=2&this_other=thing&number_is=13

问题 1: 但我不确定我是否将 raw_urlencode() 放在正确的位置,所以最好检查一下。 另外, $path 不应该像这样在 raw_urlencode 里面吗?

raw_urlencode($path)

但请注意:

raw_urlencode($path)

输出不对

问题 2: 我进一步将他们的代码更新为新版本,但输出不正确。这是为什么 ?我哪里错了? 我所做的只是添加几行。 这是我的更新(新版本)输出错误。像这样的输出:

http%3A%2F%2Fexample.com%2Fcat%2Fsubcat?var_1=value+1&var2=2&this_other=thing&number_is= 13

我在他们的代码底部添加了几行我自己的代码。

我的更新(新版本):

<?php
function encodedUrledited($url){
    $query_strings_array = [];
    $query_string_parts  = [];
    // parse URL & get query
    $scheme        = parse_url($url, PHP_URL_SCHEME);
    $host          = parse_url($url, PHP_URL_HOST);
    $path          = parse_url($url, PHP_URL_PATH);
    $query_strings = parse_url($url, PHP_URL_QUERY);

    // parse query into array
    parse_str($query_strings, $query_strings_array);

    // separate keys & values
   $query_strings_keys   = array_keys($query_strings_array);
   $query_strings_values = array_values($query_strings_array);

   // loop query
  for($i = 0; $i < count($query_strings_array); $i++){
       $k   = urlencode($query_strings_keys[$i]);
       $v   = $query_strings_values[$i];
       $val = is_numeric($v) ? intval($v) : urlencode($v);
    
       $query_string_parts[] = "{$k}={$val}";
   }

   // re-assemble URL
   $encodedHostPath = rawurlencode("{$scheme}").'://'.rawurlencode("{$host}").$path;
   
   return $encodedHostPath . '?' .implode('&', $query_string_parts);
}

if(!ISSET($_POST['url1']) && empty($_POST['url1']) && !ISSET($_POST['url2']) && empty($_POST['url2']))
{
    //Default Values for Substituting empty User Inputs.
    $url1 = 'http://example.com/cat/subcat?var 1=value 1&var2=2&this other=thing&number is=138';
    $url2 = 'http://example.com/autos/cars/list.php?state=california&max_price=500008';
}
else
{
    //User has made following inputs...
    $url1 = $_POST['url1'];
    $url2 = $_POST['url2'];
    
    //Encode User's Url inputs. (Add rawurlencode(), urlencode() and intval() in user's submitted url where appropriate).
    $encoded_url1 = encodedUrledited($url1);
    $encoded_url2 = encodedUrledited($url2);
}

echo $link1 = '<a href=' .htmlspecialchars($encoded_url1) .'>' .htmlspecialchars($encoded_url1) .'</a>';
echo '<br/>';
echo $link2 = '<a href=' .htmlspecialchars($encoded_url2) .'>' .htmlspecialchars($encoded_url2) . '</a>';
echo '<br>';

?>

这个线程实际上是关于第二个代码的。我的更新。

谢谢!

我修正了我的代码。 回答我自己的问题。

固定代码:

function encodedUrledited($url){
    $query_strings_array = [];
    $query_string_parts  = [];
    // parse URL & get query
    $scheme        = parse_url($url, PHP_URL_SCHEME);
    $host          = parse_url($url, PHP_URL_HOST);
    $path          = parse_url($url, PHP_URL_PATH);
    $query_strings = parse_url($url, PHP_URL_QUERY);

    // parse query into array
    parse_str($query_strings, $query_strings_array);

    // separate keys & values
   $query_strings_keys   = array_keys($query_strings_array);
   $query_strings_values = array_values($query_strings_array);

   // loop query
  for($i = 0; $i < count($query_strings_array); $i++){
       $k   = $query_strings_keys[$i];
       $key = is_numeric($k) ? intval($k) : urlencode($k);
       
       $v   = $query_strings_values[$i];
       $val = is_numeric($v) ? intval($v) : urlencode($v);
    
       $query_string_parts[] = "{$key}={$val}";
   }

   // re-assemble URL
   $encodedHostPath = rawurlencode($scheme).'://'.rawurlencode($host).$path;   
   $encodedHostPath .= '?' .implode('&', $query_string_parts);
   
   return $encodedHostPath;
}

if(!ISSET($_POST['url1']) && empty($_POST['url1']) && !ISSET($_POST['url2']) && empty($_POST['url2']))
{
    //Default Values for Substituting empty User Inputs.
    $url1 = 'http://example.com/cat/subcat?var 1=value 1&var2=2&this other=thing&number is=138';
    $url2 = 'http://example.com/autos/cars/list.php?state=california&max_price=500008';
}
else
{
    //User has made following inputs...
    $url1 = $_POST['url1'];
    $url2 = $_POST['url2'];
    
    //Encode User's Url inputs. (Add rawurlencode(), urlencode() and intval() in user's submitted url where appropriate).
}

$encoded_url1 = encodedUrledited($url1);
$encoded_url2 = encodedUrledited($url2);

$link1 = '<a href=' .htmlspecialchars($encoded_url1) .'>' .htmlspecialchars($encoded_url1) .'</a>';
$link2 = '<a href=' .htmlspecialchars($encoded_url2) .'>' .htmlspecialchars($encoded_url2) . '</a>';

echo $link1; echo '<br/>';
echo $link2; echo '<br/>';

?>

下面这 2 行应该在 ELSE 之外。他们不是。因此所有的问题。将它们移到 ELSE 之外,现在脚本工作正常。

$encoded_url1 = encodedUrledited($url1);
$encoded_url2 = encodedUrledited($url2);