1

私はしばらく前にこの質問を投稿しましたが、ユーザーが生成した投稿からリンクを見つけて「リンク」するのに最適です。 Linkify正規表現関数PHP大胆な火の玉メソッド

   <?php
if (!function_exists("html")) {
function html($string){
    return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}
}

if ( false === function_exists('linkify') ):   
  function linkify($str) {
$pattern = '(?xi)\b((?:(http)s?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))';
return preg_replace_callback("#$pattern#i", function($matches) {
    $input = $matches[0];
    $url = $matches[2] == 'http' ? $input : "http://$input";
    return '<a href="' . $url . '" rel="nofollow" target="_blank">' . "$input</a>";
}, $str); 
}
endif;

echo "<div>" . linkify(html($row_rsgetpost['userinput'])) . "</div>";

?>

ユーザー生成コンテンツをリンクに挿入することでセキュリティリスクが発生する可能性があるのではないかと心配しています。htmlspecialchars($string, ENT_QUOTES, 'UTF-8')linkify関数を実行してページにエコーバックする前に、データベースからのユーザーコンテンツを既にエスケープしていますが、OWASPで、XSSを軽減するためにリンク属性を特別に処理する必要があることを読みました。この関数は、ユーザー生成コンテンツを二重引用符で囲み、すでにエスケープされているhtmlspecialchars($string, ENT_QUOTES, 'UTF-8')ため、問題ないと思いますが、xssの専門知識を持つ人がこれを確認してくれると本当にありがたいです。ありがとう!

4

4 に答える 4

1

まず、データベースに入る前にデータをエスケープしてはいけませんこれは非常に重大な間違いです。これは安全でないだけでなく、機能を損ないます。文字列の値を連鎖させると、データが破損し、文字列の比較に影響します。XSSは出力の問題であるため、このアプローチは安全ではありません。データベースにデータを挿入しているとき、それがページのどこに表示されているかわかりません。たとえば、この関数を使用している場合でも、次のコードはXSSに対して脆弱です。

例えば:

<a href="javascript:alert(1)" \>

正規表現の観点から。私の最初の反応は、まあ、これは恐ろしい考えです。それがどのように機能するかについてのコメントはなく、NOT演算子を多用しているため、ブラックリストは常にホワイトリストよりも悪いです。

だから私は正規表現バディをロードし、約3分でこの入力であなたの正規表現をバイパスしました:

https://test.com/test'onclick='alert(1);//

開発者は脆弱なものを書きたくないので、プログラマーが自分のアプリケーションがどのように機能していると考えているか、そして実際にどのように機能しているかの内訳が原因です。この場合、私はあなたがこの正規表現をテストしたことがないと仮定します、そしてそれは問題のひどく過度に単純化されています。

HTMLPuriferは、HTMLをクリーンアップするように設計されたphpライブラリであり、数の正規表現で構成されています。その非常に遅く、かなり定期的にバイパスされます。したがって、このルートを使用する場合は、定期的に更新してください。

htmlspecialchars($string, ENT_QUOTES, 'UTF-8')この欠陥を修正するという点では、を使用して、文字列が「http」で始まるように強制するのが最善だと思います。HTMLエンコーディングはエスケープの一形態であり、URLが不正にされないように、値は自動的にデコードされます。

于 2012-04-26T05:39:57.607 に答える
1

データは属性に入るので、URL(またはパーセント)エンコードする必要があります。

return '<a href="' . urlencode($url) . '" rel="nofollow" target="_blank">' . "$input</a>";

技術的には、HTMLエンコードする必要があります

return '<a href="' . htmlspecialchars(urlencode($url)) . '" rel="nofollow" target="_blank">' . "$input</a>";

しかし、私が気にかけているブラウザはなく、その結果、誰もそれをしていません。あなたはすでにこのステップを実行している可能性があり、これを2回実行したくないようです。

于 2012-04-26T05:52:21.060 に答える
0

正規表現は、httpまたはhttpsのURLを探しています。この式は、URL以外のものを検出しないため、比較的安全なようです。

XSSの脆弱性は、html引数としてのURLのエスケープに起因します。つまり、URLがURL文字列を時期尚早にエスケープしてから、@Rookが言及しているhtmlタグに追加の属性を追加できないようにすることを意味します。

したがって、@ tobyodaviesによって提案されているように、XSS攻撃を次のコードで実行する方法を実際に考えることはできませんが、urlencodeを使用しないと、他のことを実行できます。

$pattern = '(?xi)\b((?:(http)s?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))';
return preg_replace_callback("#$pattern#i", function($matches) {
    $input = $matches[0];
    $url = $matches[2] == 'http' ? $input : "http://$input";
    return '<a href="' . htmlspecialchars($url) . '" rel="nofollow" target="_blank">' . "$input</a>";
}, $str); 

httpプレフィックスをチェックするための小さなショートカットも追加したことに注意してください。

これで、生成するアンカーリンクは安全になります。

ただし、残りのテキストもサニタイズする必要があります。HTMLをまったく許可せず、すべてのHTMLをクリアテキストとして表示したくないと思います。

于 2012-04-26T13:55:50.420 に答える
0

まず、PHPのドキュメントに記載されているように、ent_NOQUOTESが設定されていない場合、htmlspecialcharsは "'&'(アンパサンド)は'&''"'(二重引用符)は'"'になります。"'"(一重引用符)は''''(または')ENT_QUOTESが設定されている場合のみ'<'(より小さい)は'<''>'(より大きい)は'>'"になります。javascript:はまだ通常のプログラミングで使用されているので、:がエスケープされない理由は私を超えています。

次に、!htmlが入力されると思われる文字のみを期待している場合、入力可能で有効と見なされる文字の表現ではありません。u tf-8文字セット、および他のすべての文字セットは、同じ文字に対して複数の表現をサポートします。また、falseステートメントでは0〜9とazが許可されるため、 base64文字について心配する必要があります。私はあなたのコードを良い試みと呼ぶでしょうが、それはたくさんの改良を必要とします。または、 htmlpurifierを使用することもできますが、それでもバイパスできます。ほとんどのプログラマーはなぜそうすべきなのか理解していないので、htmlspecialcharsで文字セットを設定するのは素晴らしいことだと思います。

于 2014-01-05T23:38:39.480 に答える