如何在您的网页上安全地输出用户提交的链接?
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);
我想允许我的网站访问者(任何 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);