8

私の ASP.NET Web サイトには、Web アプリで何らかのエラーが発生したときに、私 (および別の開発者) に電子メールを送信するグローバル エラー ハンドラーがあります。最近、聞いたことのない電子メール アドレスへの CC を含むエラーを受け取りました。恐ろしいのは、エラー メールが送信される開発者のリストが、コンパイルされた ASP.NET コードにハード コーディングされていることです。CC がどのように追加されたのかはわかりません。

また、エラーの原因となったリクエストは、フォームの 1 つを使用してスパムを送信しようとしたものであるため、不正行為の可能性も非常に疑われます。リクエストを送信した IP アドレスもhttp://www.projecthoneypot.org/にリストされています。

現時点で最も推測できるのは、リクエストの形式が不正であり、CC ヘッダーが電子メールに挿入されたということです。問題は、これがどのように行われるかを理解できないことです。System.Net.Mail を使用して電子メールを送信していますが、この種のことから保護しているようです。MailMessage オブジェクトの件名は 1 行しか受け付けないため、CC 行で複数行の件名を作成することはありません。MailMessage で to および cc アドレスを設定することは、かなり堅牢なようです。また、メッセージの本文に CC ヘッダーを追加する方法がわかりません。これに関する情報が見つかりません。これが実際の問題かどうかを知りたいです。

編集: 誰かがコードを要求しました。ちょっと長いですが、以下です。

public class Global : System.Web.HttpApplication
{
    protected void Application_Error(Object sender, EventArgs e)
    {
        // Get the last exception.
        Exception objException = Server.GetLastError();

        // Work out the error details based on the exception.
        string ErrorType = "";
        string ErrorDescription = "";
        string ErrorHtml = "";

        if (objException == null)
        {
            // This should never occur.
            ErrorType = "Unknown Error";
            ErrorDescription = "Unknown Error";
        }
        else if (objException.GetType() == typeof(HttpException))
        {
            // This will occur when the ASP.NET engine throws a HttpException.
            HttpException objHttpException = objException as HttpException;
            if (objHttpException.GetHttpCode() == 404)
            {
                string Resource = Globals.GetFullUrl(this.Context);
                Server.ClearError();
                Response.Redirect("/ResourceNotFound.aspx?BadUrl=" + Server.UrlEncode(Resource));
                return;
            }
            else
            {
                ErrorType = objHttpException.GetHttpCode().ToString();
                ErrorDescription = objHttpException.Message;
            }
        }
        else if (objException.GetType() == typeof(HttpUnhandledException) && objException.InnerException != null && objException.InnerException.GetType() == typeof(HttpException))
        {
            // This will occur when the code throws a HttpException (e.g. a fake 404).
            HttpException objHttpException = objException.InnerException as HttpException;
            if (objHttpException.GetHttpCode() == 404)
            {
                string Resource = Globals.GetFullUrl(this.Context);
                Server.ClearError();
                Response.Redirect("/ResourceNotFound.aspx?BadUrl=" + Server.UrlEncode(Resource));
                return;
            }
            else
            {
                ErrorType = objHttpException.GetHttpCode().ToString();
                ErrorDescription = objHttpException.Message;
            }
        }
        else if (objException.GetType() == typeof(HttpUnhandledException))
        {
            // This will occur when a page throws an error.
            HttpUnhandledException objHttpUnhandledException = (HttpUnhandledException) objException;
            ErrorType = objHttpUnhandledException.GetHttpCode().ToString();
            if (objHttpUnhandledException.InnerException != null)
                ErrorDescription = objHttpUnhandledException.InnerException.Message;
            else
                ErrorDescription = objHttpUnhandledException.Message;
            if (objHttpUnhandledException.GetHtmlErrorMessage() != null)
            {
                ErrorHtml = objHttpUnhandledException.GetHtmlErrorMessage();
            }
        }
        else if (objException.GetType() == typeof(HttpRequestValidationException) && !Globals.IsTtiUser(this.Context))
        {
            // Do nothing.  This is mostly just spider junk and we don't want to know about it.
        }
        else
        {
            // This will occur when the ASP.NET engine throws any error other than a HttpException.
            ErrorType = objException.GetType().Name;
            ErrorDescription = objException.Message;
        }

        // Send an email if there's an error to report.
        if (ErrorType != "" || ErrorDescription != "")
        {
            Globals.SendErrorEmail(this.Context, ErrorType, ErrorDescription, ErrorHtml);
        }
    }

    public static void SendErrorEmail (HttpContext context, string errorType, string errorDescription, string errorHtml)
    {
        // Build the email subject.
        string Subject = "EM: " + errorType + ": " + context.Request.ServerVariables["SCRIPT_NAME"];

        // Build the email body.
        string Body;

        StringBuilder sb = new StringBuilder("");
        sb.Append("Server:\r\n");
        sb.Append(Globals.Server.ToString() + "\r\n");
        sb.Append("\r\n");
        sb.Append("URL:\r\n");
        sb.Append(Globals.GetFullUrl(context) + "\r\n");
        sb.Append("\r\n");
        sb.Append("Error Type" + ":\r\n");
        sb.Append(errorType + "\r\n");
        sb.Append("\r\n");
        sb.Append("Error Description" + ":\r\n");
        sb.Append(errorDescription + "\r\n");
        sb.Append("\r\n");
        sb.Append("Referring Page:\r\n");
        sb.Append(context.Request.ServerVariables["HTTP_REFERER"] + "\r\n");
        sb.Append("\r\n");
        sb.Append("Date/Time:\r\n");
        sb.Append(DateTime.Now.ToString() + "\r\n");
        sb.Append("\r\n");
        sb.Append("Remote IP:\r\n");
        sb.Append(context.Request.ServerVariables["REMOTE_ADDR"] + "\r\n");
        sb.Append("\r\n");
        sb.Append("User Agent:\r\n");
        sb.Append(context.Request.ServerVariables["HTTP_USER_AGENT"] + "\r\n");
        sb.Append("\r\n");
        sb.Append("Crawler:\r\n");
        sb.Append(context.Request.Browser.Crawler.ToString() + "\r\n");
        sb.Append("\r\n");
        sb.Append("Admin User:\r\n");
        sb.Append(context.User.Identity.Name + "\r\n");
        sb.Append("\r\n");
        sb.Append("\r\n");
        Body = sb.ToString();

        // If there's HTML to represent the error (usually from HttpUnhandledException),
        // then stuff the body text into the HTML (if possible).
        bool HtmlMessage = false;

        if (errorHtml != "")
        {
            Regex r = new Regex("(?<thebodytext><body.*?>)", RegexOptions.IgnoreCase);
            if (r.IsMatch(errorHtml))
            {
                Body = Body.Replace("\r\n", "<br>");
                Body = r.Replace(errorHtml, "${thebodytext}" + Body, 1);
                HtmlMessage = true;
            }
        }

        // Send an email to the TTI developers.
        MailMessage objMail;
        objMail = new MailMessage();
        objMail.From = new MailAddress("from-address");
        objMail.To.Add(new MailAddress("to-address"));
        objMail.CC.Add(new MailAddress("cc-address"));
        objMail.CC.Add(new MailAddress("another-cc-address"));
        if (HtmlMessage)
            objMail.IsBodyHtml = true;
        else
            objMail.IsBodyHtml = false;
        if (errorType == "404")
            objMail.Priority = MailPriority.Low;
        else
            objMail.Priority = MailPriority.High;
        objMail.Subject = Subject;
        objMail.Body = Body;

        try
        {
            SmtpClient objSmtpClient = new SmtpClient();
            objSmtpClient.Send(objMail);
        }
        finally
        {
            // Do nothing.
        }
    }
}
4

3 に答える 3

4

これは非常に創造的な攻撃のターゲットであることがわかります....ユーザーが制御するデータをメッセージ本文に詰め込んでいます...その時点で、バイナリデータを巧妙に使用すると、メッセージ中に適切なデータを送信する BODY が発生する可能性があります。 SMTP セッションをフォーマットしてJUST RIGHT ... 可能であれば、本文をすべて ASCII テキストに変換するか、文字列の構築中に、RFC 文字のみを許可する文字列サニタイザーを作成することをお勧めします (URL をフィルタリングし、 REFERRER、リモートアドレス、およびユーザーエージェント)。これらは、攻撃の可能性が高いポイントです。

次に考えられるのは、基本的な電子メールをコードで作成し、作成した本文をテキスト、HTML、または PDF ファイルとして添付することです。

SMTP ENVELOPE データはメッセージ データと同じではないことに注意してください。誰かが巧妙に正しい本文​​を送信して、本文部分で CRLFCRLF.CRLFCRLF が送信された場合、送信が終了し、その後、彼らがデータを送信し続ければ、MAIL FROM: RCPT TO:, DATA など全体を送信できます... (確かに、これはありそうもないシナリオです...)...

あなたが受け取った電子メールの生のソースを見てみたいです... (実際の SMTP トランザクションの 16 進ダンプのように、Outlook があなたに見せたいものなどではありません)。

メッセージを送信する前に、QP または B64 を使用してボディをエンコードすることもできます。これにより、問題が解決する可能性があります。

これは面白いので、結果が楽しみです。

于 2009-03-18T00:26:51.840 に答える
1

あなたのコードは非常に安全に見えるので、問題はあなたの側にあるとは思いません.

IMO、メールサーバーに送信されている間に誰かが SMTP メッセージを傍受し、余分な CC: 行を挿入したかのどちらかです。またはメールサーバーが危険にさらされています。

答えが見つからない場合は、Microsoft に直接問い合わせることをお勧めします。.NET Framework のエクスプロイトを発見した可能性があります。

于 2009-03-18T11:05:51.773 に答える
0

回避策として、非対称暗号化 (公開鍵暗号化など) を使用して電子メール メッセージを暗号化してみませんか? そうすれば、意図した受信者だけがそれを読むことができます。

このようにして、悪者があなたのメッセージのコピーを (何らかの手段で) 取得したとしても、それは彼らの役に立ちます。

FBIやGoogleのような知名度の高いWebサイトを持っている場合、多くの非常に創造的な人々が多くの時間を費やし、それを妥協するために多大な努力をします. 詳細なエラー メッセージを保護することは非常に重要です。

于 2009-07-19T18:35:29.797 に答える