web-dev-qa-db-ja.com

php-FILTER_SANITIZE_EMAILは無意味ですか?

登録フォームを作成しているだけで、データベースに有効で安全な電子メールを挿入することだけを考えています。

いくつかのサイト(w3schoolsを含む)は、安全のためにFILTER_VALIDATE_EMAILを実行する前にFILTER_SANITIZE_EMAILを実行することを推奨しています。ただし、これにより、送信された電子メールが無効な電子メールから有効な電子メールに変更される可能性があります。これは、ユーザーが望んでいたものではありません。

ユーザーのメールアドレスはjeff!@ gmail.comですが、誤ってjeff "@ gmail.comを挿入しています。

FILTER_SANITIZE_EMAILは、「ユーザーの実際の電子メールアドレスではなくても、FILTER_VALIDATE_EMAILが有効であると言う電子メール[email protected]を作成する」を削除します。

この問題を回避するために、FILTER_VALIDATE_EMAILのみを実行する予定です。 (無効と宣言された電子メールを出力/処理するつもりはないと仮定します)

これにより、メールが有効かどうかがわかります。もしそうなら、FILTER_SANITIZE_EMAILを通過する必要はないはずです。なぜなら、違法/安全でない文字は、すでに電子メールが無効に返される原因になっているからですよね?

また、空白、括弧()、セミコロンによって電子メールが無効になるため、FILTER_VALIDATE_EMAILによって有効であると承認された電子メールがinjection/xssに使用される可能性があることも知りません。それとも私は間違っていますか?

(注:これに加えて、プリペアドステートメントを使用してデータを挿入します。これをクリアしたかっただけです)

26
Alex

有効なメールのみを挿入する方法は次のとおりです。

<?php
$original_email = 'jeff"@gmail.com';

$clean_email = filter_var($original_email,FILTER_SANITIZE_EMAIL);

if ($original_email == $clean_email && filter_var($original_email,FILTER_VALIDATE_EMAIL)){
   // now you know the original email was safe to insert.
   // insert into database code go here. 
}

FILTER_VALIDATE_EMAILおよびFILTER_SANITIZE_EMAILはどちらも価値のある機能であり、さまざまな用途があります。

検証では、電子メールが有効な形式であるかどうかをテストしています。サニタイズとは、メールから悪い文字を取り除くことです。

<?php
$email = "[email protected]"; 
$clean_email = "";

if (filter_var($email,FILTER_VALIDATE_EMAIL)){
    $clean_email =  filter_var($email,FILTER_SANITIZE_EMAIL);
} 

// another implementation by request. Which is the way I would suggest
// using the filters. Clean the content and then make sure it's valid 
// before you use it. 

$email = "[email protected]"; 
$clean_email = filter_var($email,FILTER_SANITIZE_EMAIL);

if (filter_var($clean_email,FILTER_VALIDATE_EMAIL)){
    // email is valid and ready for use
} else {
    // email is invalid and should be rejected
}

PHPはオープンソースであるため、これらの質問はPHPを使用するだけで簡単に回答できます。

FILTER_SANITIZE_EMAILのソース

/* {{{ php_filter_email */
#define SAFE        "$-_.+"
#define EXTRA       "!*'(),"
#define NATIONAL    "{}|\\^~[]`"
#define PUNCTUATION "<>#%\""
#define RESERVED    ";/?:@&="

void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
{
    /* Check section 6 of rfc 822 http://www.faqs.org/rfcs/rfc822.html */
    const unsigned char allowed_list[] = LOWALPHA HIALPHA DIGIT "!#$%&'*+-=?^_`{|}~@.[]";
    filter_map     map;

    filter_map_init(&map);
    filter_map_update(&map, 1, allowed_list);
    filter_map_apply(value, &map);
}    

FILTER_VALIDATE_EMAILのソース

void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
const char regexp[] = "/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD";

pcre       *re = NULL;
pcre_extra *pcre_extra = NULL;
int preg_options = 0;
int         ovector[150]; /* Needs to be a multiple of 3 */
int         matches;


/* The maximum length of an e-mail address is 320 octets, per RFC 2821. */
if (Z_STRLEN_P(value) > 320) {
    RETURN_VALIDATION_FAILED
}

re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC);
if (!re) {
    RETURN_VALIDATION_FAILED
}
matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);

/* 0 means that the vector is too small to hold all the captured substring offsets */
if (matches < 0) {
    RETURN_VALIDATION_FAILED
}

}
23
jbrahy

これを行う「適切な」方法は、ユーザーの電子メールを2回要求することです(これは一般的/グッドプラクティスです)。しかし、あなたの質問に答えるために、FILTER_SANITIZE_EMAILは無意味ではありません。これは、電子メールをサニタイズするフィルターであり、その役割を果たします。

validates のフィルターはtrueまたはfalseを返すのに対し、 sanitizes のフィルターは実際に指定された変数を変更することを理解する必要があります。 2つはnotは同じ目的を果たします。

5
David Titarenco

私は同じ記事を読み、同じことを考えました。無効な変数を変更するだけでは十分ではありません。問題を無視するのではなく、実際にユーザーに問題があったことを伝える必要があります。解決策は、オリジナルとサニタイズされたバージョンを比較することだと思います。つまりw3schoolsの例を使用するには、次を追加するだけです。

$cleanfield=filter_var($field, FILTER_SANITIZE_EMAIL);
if($cleanfield != $field){
return FALSE;
}
3
TamaMcGlinn

車輪の再発明をしないでください、あなたのメールサーバーに仕事をさせてください:適切な 電子メールの検証/妥当性確認は複雑すぎる問題です すべてを手作業で行うには。例えば。実際、有効な電子メールには、RFC2822に従ってスペースが含まれている場合があります。 [〜#〜] idn [〜#〜] についても言及していません。

XSSの安全を確保するために、すべての出力をエスケープします。通常どおりSQLパラメータをエスケープします。準備されたクエリを使用します。すべての入力と出力を適切にエスケープすれば、データベースに何を保存するかは問題ではないため、この種のデータをサニタイズすることは無意味です。

結論:

  • 基本的な正しさについてのみメールをチェックしてください。
  • 必要に応じてFILTER_VALIDATE_EMAILを使用し、
  • ユーザーが送信したデータにFILTER_SANITIZE_EMAILを使用しないでください。

(PHP FILTER_VALIDATE_EMAILの一部の古いバージョンでは、一般的なインターネットWebサイトではうまく機能しなかったことに注意する価値があるかもしれません。john@gmailは有効なメールです。)

1
sanmai