例によって物は試しということで、話題のnoteに投げ銭箱置いてみました。
OpenSSLの記事が少しでも役に立ったー、とか、note.muの購入機能試してみたい、とかいう奇特な人が居たらどうぞ。売上はご報告の上でラーメン代の足しにします。
ちなみに、私自身は尊敬している結城先生の記事に投げ銭してみました。
影響を受けたウェブサイトやソフトウェアの対応については、piyologさんの以下の記事に詳しいです。
この記事では、それ以外の動きについてまとめていきます。先週の2つの記事と違い、あくまで個人的興味によるものです。
【おしらせ】 国民のための情報セキュリティサイトでは、OpenSSLの脆弱性に関する注意喚起を掲載しました。#総務省 #情報セキュリティ #SSLURL
2014-04-16 08:18:54 via web
これまでに4万件以上確認され、今月12日の午前3時からは1時間で最も多い5088件が検知
remove FIPS mode support. people who require FIPS can buy something that meets their needs, but dumping it in here only penalizes the rest of us.意訳: FIPSなんて金持ちの道楽知らんボケ
皆さんご存じのとおり、トリプル握手は有害と思われ。そこにはこんな一文も: 「主要な TLS 実装はどれも素数判定をしていない。」 (訳注: TLS のリジュームと再ネゴの両方が可能な善良サーバに対して、同じクライアント証明書を受け取ることのある悪サーバが MITM できる。DH の場合、pre-master secret を制御するために素数どころか偶数を使う exploit が可能で、たいていバレない)
JVNやJPCERT/CCの記事があまりにもさらっと書かれていて、具体的なリスクが想像しづらいと思うので説明します。
他にも色々漏れてますが、とりあえずエンジニア以外の人が覚えておくべきはここまででOKです。もう少し分かりやすい情報が以下にあります。
まだ直っていないウェブサイトもあれば、元々壊れていないウェブサイトもあるので、「直したからパスワード変更してね」って言ってきたら変更してください。あと、悪い人が偽メール送ってきているので、メールで連絡してきたとしても、ブラウザのブックマークから開きましょう。
ここからはエンジニア向けの詳細です。
いわゆる「SSL通信」と呼ばれる暗号化通信は、実際にはSSL 3.0とより新しいTLS 1.0〜1.2(互換性のためプロトコル上の番号は3.1〜3.3)というプロトコルで定義されています。これらを使うために、様々なソフトウェアが利用している共通ライブラリが OpenSSL です。今回の脆弱性は、このTLS 1.2に追加されたハートビート拡張*1の実装の不具合によるものです。
SSL通信の最初「ハンドシェーク」段階でSSL証明書の検証などを行いますが、今回の脆弱性はそのハンドシェーク段階の中でも発生する*2ため、正しいSSL証明書を持っていなくても攻撃が成立します。ほとんどの場合にログが残らないのもこのためです。
攻撃者は、通信の相手のメモリ内容を取得することができます。一回で最大64キロバイト、同じプロセス内の情報に限られますが、ログに残らず、めぼしい情報が取得できるまで何度でも繰り返すことができるため(これがメモリガチャと呼ばれる理由)、プロセス内の全ての情報が漏洩したと考えるべきです。
「同じプロセス」というところが問題で、どのプロセスがSSL通信をしたかによってリスクが大きく変わります。
ロードバランサーはSSLのサーバ側として、SSL証明書の秘密鍵をメモリ内に保持します。この秘密鍵が攻撃者に漏洩します。
SSL処理をしているところでデータが漏洩した場合のリスクは、大きく三つあります。
(これは、Apache等でSSL処理をしている場合も同様です!)
空きメモリ内には、直前の通信内容がクリアされず残っている場合があります。SSL処理が終わり復号された平文の通信内容もふくまれるため、以下のような攻撃が成立します。
特に意識せず設定されたSSLサーバの場合、SSL証明書の秘密鍵を知っている攻撃者は、暗号化されているはずの通信内容を復号して、内容を見ることができます。
特に、毎年SSL証明書を更新する毎に秘密鍵を作り直していなかった場合、過去の通信内容を保存している組織*3があった場合、過去に遡って全ての通信内容を復号して、そのなかのあらゆる情報を知ることができます。たとえ毎年秘密鍵を生成し直していた場合でも、直近の最大1年間の通信内容は全て筒抜けです。
これに対しては、Forward Secrecyという対策が存在します。
ただし、これまで必要性が重要視されなかった(まさかこれほど大規模に秘密鍵が漏洩する脆弱性が見つかるなんて思われていなかった)、性能が従来のRSAより若干遅い、などの理由があってあまり普及していません。今回を良い機会として、利用している暗号化アルゴリズムを見直し、Forward Secrecyを有効にするのが良いでしょう。Verisignから証明書ビジネスを引き継いだSymantecは以下のように主張しています。
結論として、ウェブサイトが RSA から離れて Forward Secrecy を提供するとともに、極めて低速なDHEよりもECDHE 鍵交換を配備することを、我々は強く推奨します。
たとえば、sns.example.jp というSNSのSSL証明書秘密鍵が漏洩したとします。攻撃者はすかさず、その秘密鍵を使って、sns.example.jp の正当なSSL証明書を持った偽サーバを公開できます。公衆Wifiを使っていたり、DNSへの攻撃を併用すれば、その偽サーバにアクセスさせることができます。
アドレスバーを見ろと言ったところで正しいドメインで鍵が表示されているわけですし、たとえEV-SSL証明書を使ってアドレスバーを緑に染め上げていたとしても、全く同じ証明書でサーバを用意されてしまっては無力です。
これが、脆弱性のあるバージョンを使っていた場合に証明書の再発行だけでなく、「失効」が必要となる理由です。
アプリケーションサーバの前段にApacheやnginxを設置し、そこでSSL処理を行っていた場合です。
ロードバランサーの場合に加えて、以下の情報が漏洩します。
mod_php5やmod_perlなどを利用し、Apacheモジュールとしてウェブアプリケーションを動かしていた場合です。
これまで登場した全ての内容に加えて、以下の内容が漏洩します。
ここまでくると、想定されるリスクはかなり大きいです。
PHPであっても、PHP-FPMを使うなどApacheとプロセスを分けることで、権限ごと分離できるので、今回を期に挑戦すると良いのでは無いでしょうか*4。
SSH系を除くほぼ全てのクライアントアプリケーションの暗号化通信が当てはまりますし、サーバ側であっても、外部のAPIサーバへの通信などにはあてはまります。
あくまでこの場合、攻撃者が用意したサーバに接続しない限り安全であると考えられますが、その一方で、DNSキャッシュポイズニングやBGPのハイジャックなど、攻撃する側がトラフィックを呼び込むための手法が存在しています。
これをされた場合、そのクライアントが持っている接続先リストやそこに含まれるユーザー・パスワードが漏洩します。
外部に接続するサーバ側アプリであれば、前述の「ApacheでSSLを提供し、脆弱性があった場合 (mod_php5,mod_perl等)」と同等です。例えばSSLサーバとしては社内からの接続しか受けていなかったとしても、抜け道があるので、やはり上げておきましょう、ということです。
必要な情報は http://heartbleed.com/ にまとまっているのですが、英語だし長いしって人のために手短にまとめておきます。
漏洩する情報の具体例は、OpenSSLの脆弱性で想定されるリスクとして別の記事に書きましたのでそちらをご覧くださいまし。
基本的には、パッケージ更新などでOpenSSLをバージョンアップして、そのあとOpenSSLを読んでいるサービスを再起動します。外部サーバへの接続なども含めるとOpenSSLを利用するサービスが多いので、よく分からない人はサーバごと再起動がおすすめ。
1.0.1からの新機能による脆弱性なので、1.0.0とそれ未満であれば問題ありません。逆に、1.0.1eやそれ以前のバージョン番号のまま脆弱性のみ修正される場合もあるので、OpenSSLのバージョンだけでなく、パッケージのバージョンを確認してください。
ディストリ | どうすればいいか |
---|---|
Debian Wheezy (stable)以降 | DSA-2896-1 stable: libssl1.0.0 1.0.1e-2+deb7u5 で修正 testing/unstable: libssl1.0.0 1.0.1g-1 で修正 |
Ubuntu 12.04.4 LTS以降 | [USN-2165-1] 12.04: libssl1.0.0 1.0.1-4ubuntu5.12 で修正 12.10 libssl1.0.0 1.0.1c-3ubuntu2.7 で修正 13.10 libssl1.0.0 1.0.1e-3ubuntu1.2 で修正 |
RHEL 6.5 | [RHSA-2014:0376-1] openssl-1.0.1e-16.el6_5.7で修正 |
CentOS 6.5 | [CESA-2014:0376] openssl-1.0.1e-16.el6_5.7 で修正 |
Scientific Linux 6.5 | openssl-1.0.1e-16.el6_5.7 で修正 |
Fedora 18以降 | [Bug 1085065] Fedora 19: openssl-1.0.1e-37.fc19.1 で修正 Fedora 20: openssl-1.0.1e-37.fc20.1 で修正 (Fedora 18はサポート切れのため公式パッケージ無し) |
OpenBSD 5.3以降 | [Patches for OpenSSL bounds checking bug] パッチあり: 5.3 / 5.4 / 5.5 |
FreeBSD ports | [[ports] Revision 350548] security/openssl 1.0.1_10 で修正 |
FreeBSD 10.0 | [FreeBSD-SA-14:06.openssl] freebsd-updateでバイナリ更新するかpatchあててbuildworld/installworld/reboot |
NetBSD pkgsrc | [NetBSD Security Advisory 2014-004] openssl-1.0.1gで修正 |
NetBSD 6.0以降 | [NetBSD Security Advisory 2014-004] 各arch向けにビルド済みバイナリが配布されている。 |
OpenSUSE 12.2 | [openSUSE:Maintenance:2718] |
Amazon Linux 2013.03以降 | [Thread: openssl heartbleed] ALAS-2014-320: openssl Security Update - Information Disclosure Vulnerability] 2013.09: openssl-1.0.1e-4.58.amzn1 で対応 2014.03: openssl-1.0.1e-37.66.amzn1.x86_64 で対応 |
Amazon ELB | [HeartBleed Bug Concern] [AWS Services Updated to Address OpenSSL Vulnerability / 参考和訳] 全てのRegionで対応済み、ただし証明書の更新を推奨 (リスクの度合いは不明) |
Amazon CloudFront | [AWS Services Updated to Address OpenSSL Vulnerability / 参考和訳] 対応済み、ただし証明書の更新を推奨 (リスクの度合いは不明) |
Homebrew | [openssl 1.0.1g] brew update brew upgrade openssl brew link openssl --force (コメ欄にて詳しい手順有り) |
Gentoo Linux | [GLSA 201404-07 / openssl] dev-libs/openssl-1.0.1g で修正 |
BIG-IP | [SOL15159: OpenSSL vulnerability CVE-2014-0160] 11.5.0以降が影響を受ける模様 「Use only Native SSL stack ciphers」に設定していれば回避可能 |
Google Compute Engine | [Security Bulletins] 各ディストリの v20140408 以降のイメージで作り直すか、yum/aptでパッケージ更新 |
Android 4.1.1 | [Google Services Updated to Address OpenSSL CVE-2014-0160 (the Heartbleed bug)] Android 4.1.1のみ影響 ChromeはOpenSSLを使わない(NSS)のため影響外 |
自前で入れたり、バージョンアップがすぐにできない場合は、「-DOPENSSL_NO_HEARTBEATS」を設定し、OpenSSLをコンパイルしてもよい。
ソフトウェア | 対応 |
---|---|
Cygwin | [Updated: openssl-1.0.1g-1] openssl-1.0.1g-1 で対応 |
影響無し 当初「SSH部分に影響無し、TTProxyでSSL利用時のみ影響を受ける可能性」と書いていましたが、今のところSSL通信をしないとのこと[出典] |
|
Apache mod_spdy | 独自OpenSSLを内部で持つのでv0.9.4.2に上げる(出典) |
Phusion Passenger | [Phusion Passenger 4.0.41 released, OpenSSL Heartbleed security update] OpenSSLを静的リンクしており4.0.41未満で影響あり |
Ruby RVM | [rvm/config/db] rvm管理下で別にopensslを入れた場合は対応が必要 |
Ruby rbenv/ruby-build | [OpenSSL library updated to 1.0.1g #547] ruby-buildプラグインで別にopensslを入れた場合は対応が必要 plugins/ruby-build下でgit pullしてrbenv installしなおす |
OpenVPN | [OpenVPN 2.3.2 Windows build I004 リリース] [OpenSSLの脆弱性 – Heartbleed について] Windows版バイナリにOpenSSLが含まれるため、OpenVPN側のバージョンアップも必要。 Android版クライアントもAndroid 4.1(.0)と4.1.1は影響を受けるのでAndroid対応待ち 修正(2014/04/10 18:24) TLS-Authの記述が逆になっていました。TLSハンドシェークの前にHMACによるチェックを挟む機能で、有効にしていれば影響を受けません。こちらの記事に詳しく書かれています。 |
FFFTP | [臨時版 1.98g1 - FFFTP] FTPS(FTP over TLS/SSL)のみ影響、1.98g1 で対応 |
WinSCP | [OpenSSL vulnerability CVE-2014-0160] 5.5.3で対応予定 通常のSCP/SFTPには無関係、FTP over TLS/SSLを使っている場合のみ影響 |
OpenSSLに脆弱性があり、SSLで通信している相手のメモリを閲覧できます*1。
具体的には、以下のようなシナリオが考えられます。
脆弱性のあるバージョンを使っていた場合、最悪でSSL証明書の秘密鍵が奪取されている可能性があります。この場合、現在使っているSSL証明書を失効(revoke)させ、再発行する必要があります。
証明書の失効方法については、SSL証明書を発行したCAに問い合わせてください。CA側で管理する証明書失効リストに掲載され、漏洩した秘密鍵によるSSL証明書が使えないようになります。例えばSymantec(旧Verisign)であればストアフロントから失効申請ができるようです。
We were contacted by the OpenSSL team in advance. As a result, Akamai systems were patched prior to public disclosure.カコイイ
警察庁の定点観測システムにおいても、9日以降、当該攻撃コードに実装されているClient Hello パケットと、完全に一致するパケットを多数観測しています。このことから、同攻撃コードを使用して、脆弱性が存在するサーバ等の探索が実施されているものと考えられます。
9. サーバIDの再発行にはどれくらい時間がかかりますか?
シマンテックの営業時間に申請した場合には即日または翌営業日、営業時間外に申請した場合には翌営業日の発行となります。
正常にインストールが出来ましたら、旧証明書の失効化をご依頼下さい。
失効化の方法は方法が決まり次第、別途ご連絡申し上げます。
この記事はおひとりさま Monitoring Advent Calendar 2013の1日目です!
「あの値とその値の変化を一週間だけ取ってグラフで見たい!」
そんなことってありませんか?自分はまれによくあります。
そんな貴方におすすめなのが、この記事で紹介する常設GrwothForecastとgrouthforecast-workerの組み合わせです。慣れると、必要になってから5分もあれば値の取得が始められるようになります。
GrowthForecastは単体でWebサーバとして起動して、放り込んだ値をうまいことグラフ化してくれるソフトウェアです。インストールの方法は、公式サイトにCentOSやUbuntuでそのまま使えるコマンドで書いてあります。
デフォルトではTCP5125番ポートで起動するので、ファイアウォールで開けるなりリバースプロキシするなりしておきます。
API投稿をlocalhostなどに制限するallow-fromオプション等もあるので、慣れてきたらそのあたりも調整していくと良いと思います。
次に、grouthforecast-workerをインストールします。
githubにありますが、必要となるのはPerlスクリプト1ファイルです。wgetなどで取得して実行権限を立ててください。また、後ほど使うmetrics_scriptという空ディレクトリもここで用意しておきます。
% cpanm -n Path::Class % wget https://raw.github.com/yappo/grouthforecast-worker/master/grouthforecast.pl % chmod +x grouthforecast.pl % mkdir metrics_script
スクリプト内の二箇所を変更します。
# GrowthForecast の /api の URL my $growthforecast_endpoint = 'http://localhost:5125/api'; # グラフをどのサービスに属するかを example の変わりに入れてね my $service_name = 'metrics';
もうひとつ、起動スクリプトを用意します。とりあえずfetch.shとでもしておきます。
#!/bin/bash $(dirname $0)/grouthforecast.pl $(dirname $0)/metrics_script
この起動スクリプトをcrontabに登録します。
*/5 * * * * /(ファイルを置いたパス)/fetch.sh
ここまでを「常設GrowthForecast環境」として、暇なときにでも、お手元にあるroot権限があるVPSなどにいれて立ち上げっぱなしにしておきましょう。
グラフにしたい数字をただ表示するだけのプログラムを作ります。シェルスクリプトでもRubyでもPerlでもPHPでもJavaでもなんでもかまいません。とにかく数字を表示してください。
たとえば、DBにクエリを投げてユーザ数を取りたければこんな感じです*1。
#!/bin/bash echo 'SELECT COUNT(*) FROM users;' | sqlite3 /foo/bar/foobar.db
もうちょっと複雑な例として、先日行われたANIMAX MUSIXの三森すずこチャリティオークションの落札金額であれば、スクレイピングしてくるスクリプトをこんな感じで用意すれば良いです。ほとんど、どっかに転がっているサンプルコードそのままです*2。
#!/usr/bin/env perl use strict; use warnings; use Web::Scraper; use Data::Dumper; use URI; my $uri = new URI('http://www.pashaoku.jp/auction/detail/34875092'); my $scraper = scraper { process '.itemAuctionInfoData', 'yen' => 'TEXT'; }; my $res = $scraper->scrape($uri); if ($res->{yen} =~ m/([0-9,]+)$/) { my $yen = $1; $yen =~ tr/,//d; print $yen; } print "\n";
この例だと変数 $uri を変更したファイルをいくつか用意しておけば*3、複数のオークションの価格を同時に比較することができます。
実行したら数字を表示するプログラムが用意できたら、先ほどこっそりつくっておいた metrics_script ディレクトリに、さらにもう一階層切ってから放り込みます。実行権限も付けておいてください。
grouthforecast.pl + metrics_script + db + users (DBからのユーザ数取得プログラム) + auction + mimorin (オークション価格取得プログラム)
はい、これでおしまいです。
10分ぐらい待てば値を2回取ってきて最低限のデータが揃うので、早速見てみましょう。
http://(サーバーのホスト名やIPアドレス):5125/
一覧ですね。それぞれクリックすればグラフが見られます。
ね、簡単でしょ?
grouthforecast.plで設定した$service_nameと、スクリプトのディレクトリ、ファイル名がそのままグラフのパスになります。とにかく値さえ取っておきさえすれば、あとからAPIドキュメントにあるとおりグラフのURLをいじってあげると、複合グラフや期間指定も自由自在です。
*1:参考までに、MySQLなら--defaults-fileでオプションファイルを利用するとコマンドラインにパスワード書かずにすみます。http://dev.mysql.com/doc/refman/5.1/ja/option-files.html
*2:Web::Scraperモジュールが必要なので、cpanm -n Web::Scraper などしてください。
*3:もちろんDRYではありませんが……
SQLへの安全な値の埋め込み方について、ここ数日で色々議論というか意見の投げ合いがありましたが、自分としての考えをまとめておきます。
新規に開発する場合、99%以上はこれで十分なはずです。
値を埋め込まない静的SQLのみで、RDBMSがAPIとして提供しているプレースホルダだけを使っている限り、絶対に安全です。もしそうでないとしたらそれはRDBMSの脆弱性です。
ぱっと見プレースホルダっぽく見えて、ライブラリの中で値を埋め込んでRDBMSに投げている実装がたまにあるようなので、そういう場合はそこに脆弱性が存在する可能性が高まります。そのあたりは自分の使うライブラリやフレームワークの情報を収集してください。有名なところだと、PHPのPDOが提供する「動的プレースホルダ」がこのような実装になっていて、実際にShift_JISを利用した場合に脆弱性がありました。
なお、全てのRDBMSで使えるかどうかは分かりませんが、ストアドプロシージャを利用することで、テーブル名等についても展開が可能です。
ただし実装が不必要に複雑になったり、ストアドプロシージャが様々な理由で使えない場合もあるかと思います。そこで。
プレースホルダが利用できない(しづらい)状況として、日付や何らかの識別子をテーブル名(やパーティション名)に使わなくてはいけない場合があります。また、ソート順のORDERにカラム名を入れる場合などもあります。
その場合は、自分で生成した日付や、マスタデータとして持つ文字列など、文字種が完全に固定されたもののみを組み合わせるのであれば、その生成処理が正しく動いている限りリスクは。エスケープの必要の無い文字種のみを使うような設計をすれば良いです。
WordPressやMovableType等でつかわれている「テーブル名プレフィックスという外部入力値」については、設計として「英数字とアンダースコアだけを使う」と決め、その通りに入力バリデーションを実施していれば、やはりエスケープの必要は無いはずです。
安全な設計をしましょう。
RDBMSの管理ツールなどをあなたが実装しているのであれば、ユーザがうっかり作ってしまった記号まみれのテーブル名に対してもアクセスできないといけないかもしれません。
おめでとうございます!
ここまできて初めてエスケープが必要となります。
個人的には、RDBMSのエスケープAPIや既存のライブラリを用いて「プレースホルダに値をエスケープして埋め込む」という関数をきっちり作り込み、そこに集約させるのが良いのでは無いかな、と思います。
決して、エスケープ処理自身を一から自分で書こうだなんて恐ろしいことを考えないでください。
その必要があるのは、あなたがRDBMS自身やそのライブラリの開発者の場合だけです。
SQL文字列に直接値をエスケープして埋め込んだコードが既にあり、修正する手間を掛けられない人。
正しいエスケープでもプレースホルダの利用に切り替えるでもリスクの許容でも好きな手法をお選びください。
エスケープする場合は上に書いたとおりです。
アプリケーション開発者にとって、SQLインジェクション対策において必要な知識は、これに尽きると思います。
こちらの記事で指摘されるようなプリペアドステートメントのデメリットはありますが、「静的SQL+プレースホルダ」の安全性と比較してもなお動的SQLが必要となる状況であれば、設計を見直すべきだと考えます*1。
SQLに限らず「エスケープは難しい」という認識は、全てのエンジニアが持っているべきです。
その認識が無いからこそ、プレースホルダが使える状況にもかかわらず動的にSQLを組み立ててしまうエンジニアが後を絶ちません。
大事なことを書き忘れましたが、SQL文法上の「エスケープ」の話です。
例えばLIKE句に食わせる文字列値の中の % や正規表現のメタ文字など、「文字列の中身」で必要なエスケープはもちろん必要ですし、そこから先こそこそがアプリケーションの責務だと考えます。もちろん「エスケープが必要な場面そのものを可能なかぎり減らせ」という主張は変わりません。
理想を言えば、LIKE句や正規表現などエスケープが必要な処理全てに対応する組み込み関数や、先頭一致を示すオペレータがRDBMS側で用意されていると、アプリケーション側でのエスケープが必要なくなり、より安全になるのではないかなと考えています。
*1:このあたりはさすがに宗教かなとは思います。
定期的に繰り返される話題ですがまた盛り上がっているのできちんと書いておきます。
「通るべきメールアドレスが弾かれると激おこ」という前提で話を進めます。
2009年以前に登録されたDoCoMo携帯のメールアドレスなど、quoted-stringじゃないのにピリオド連続するものが実在している以上、彼らを許容するべきです。
今そこにある実装 >>(越えられない壁)>> RFC です。
@の左側(addr-spec)でUTF-8を利用できるようにするRFC5335が発行されています。これにより、通すべき文字が一気に増えます。
通常、電子メールアドレスは「ユーザー名@ドメイン名」という形式で表されます。そのうち、@の右側の「ドメイン名」の国際化については、国際化ドメイン名(IDN)として、既に標準規格が定められています。今回の国際化電子メールアドレスは、@の左側の「ローカルパート」と呼ばれる部分も含んだメールアドレス全体の国際化を行い、電子メールアドレスの任意の部分に、日本語を含むさまざまな言語の文字を使用可能にするための技術です。
また、そもそもドメイン部はとっくに国際化されています。こちらはPunycodeでデコードされた「xn--***.jp」というドメインを使えばいいわけですが、真にユーザーの利便性を考えるなら国際化ドメインを直接入力できるべきでしょうね。ははは。
結局のところ「メールアドレスのルール」というのが現実としてどんどん変わっていく以上、これを元にバリデーションを掛けるのは人類にはまだ早すぎます。
で、そんな厳しくバリデーションしたところで、「メールアドレスのルール」を逸脱しない範囲での打ち間違えの方が多いです(例: foobar@example.jpo)。
TLDのホワイトリストなんて新gTLDがぽこぽこ量産される時代に持っちゃいけません。
これが一番早いです。余程偏った利用者層でない限り、メール内のURLクリックというインターフェースにユーザーも慣れています。
ちなみに本件とは別ですが、メールアドレスの打ち間違えで別の人に届くリスクがあるので、メール内のURLクリック後に無条件にログイン状態にしてしまうと危険だったりします。
「"」でくるむquoted-stringなんて使っている人ほとんど居ないのでその部分は忘れ、普通に使う事ができる記号「!#$%&'*+-/=?^_`{|}~.」は受け取るようにします。
これでほとんどの人が救済される上、バリデーション部分の正規表現の変更のみと変更コストが最も低いです。ただ、当然ながらRFCに準拠して作られたマニアックなメールアドレスは受け取れません。
上にも書いたとおり仕様や現実が変わっていく以上大変ですが、それに見あう効果があるかというと自分は見あわないと思います。
とはいえ、技術的トライアルとしては楽しそうなので、だれかやってください(他力本願)。
メールは送りたくないが、せめてドメイン部は、という事であればDNSのMXレコードとAレコードを引きましょう。
当然ながら、@の左側の打ち間違えには無力ですし、フィッシング用の偽ドメインが存在してしまう場合もあります。
実際にDNSを引いて調べた相手先メールサーバにSMTPで接続し、RCPTコマンドを送るところまでやってみることで、存在しないユーザーであればエラーを返してくれる場合が多いです。
ですが、DNSを引くのに比べてずっと時間が掛かるのでウェブアプリの1リクエスト中では厳しくなります。
昨今では、エラーを返さず受け取るだけ受け取って迷惑メール事業者フラグを立てるという実装もありそうな気がしますし、そもそも相手のメールサーバにメールを送らないのに無駄に接続する以上、負荷を掛ける行為にもなりかねません。
というわけで、理論上はできそうと言うだけで、やらない方が良いでしょう。非推奨ということで敢えて入れました。
メールアドレスの確認はそこにメールを送る事で確認を行いましょう。
入力フォーム段階でのバリデーションは、フィールドの入れ間違い等への対策として「@」や「.」を含むどうか程度に留めべきです。
補足: 重要なのは「その仕様で誰が得をするか」をよく考えましょうってことです。どうしてもバリデーションだけで頑張りたいのであれば、""なしで使える記号を許容すると、対応が楽な割に救済される人が一気に増えます。逆に、絶対に厳密な入力制限が必要な場合は、死ぬ気で頑張るしかないでしょう。