Help us understand the problem. What is going on with this article?

外部サイトへの遷移させるとき注意すべき1つのこと

More than 3 years have passed since last update.

SNSなどプライベートな記事をユーザが書けるページから、外部サイトへリンクする場合、リファラーによって秘密のURLが漏洩しないように、リダイレクト専用のアプリを用意することがあります。
また、自サイトからの外部サイトへの遷移を把握するためにも、そういうリダイレクト専用アプリを用意してログを落とすようにすることがあります。

これは、特に何もしないと格好のフィッシング詐欺の踏み台になります。

https://www.facebook.com/l.php?u=http://i.am.fishing/

みたいなリンクを、どこかの掲示板などに貼られると、「おっ、フェイスブックのリンクじゃん」
ってことで、踏んでしまう人がいるからです。

対策です。

:skull: リファラチェック

HTTP_REFERERが自サイト以外だったら、エラーにする設計です。あまりないとは思いますが、こういう設計をされているサイトを見かけたことがあります。

当然ながらRefererはクライアントの設定で送らないように容易にできます。(auのガラケーブラウザはRefererを送らないってことも、昔はありました。)

そういう、ふつうのユーザが、外部サイトへの遷移ができなくなってしまうので、この設計はやめましょう。

:confused: ホワイトリスト

ある程度外部リンクをコントロールできる場合は、遷移可能なサイトへのURLをリスト化しておき、チェックする方式をとることがあります。

たいていリダイレクト専用のアプリケーションなんて汎用的なものは、時間が経つと、当初と違う用途で使われたりするようになります。そうすると、最初は大したことないから、と始めたホワイトリストのメンテナンスがエラい大変になってきた、なんてことになります。(みたいなことが以前ありました)

なので、そういう恐れがあれば、これもやめたほうが良いです。

:grinning: ハッシュコード

これがふつうの方式です。ロケーションURLを元にしたHMACを付けます。これがない、またはHMAC値が一致しない場合は、エラーにするか、"外部サイトに移動しようとしてますがよろしいですか?"みたいなページを挟むようにします。

image

Facebookだとこんな感じです。

Javaでの実装

HMACの鍵でURLを作ります。

    public String redirectUrl(String url) throws UnsupportedEncodingException {
        return "/redirect?u=" +  URLEncoder.encode(url, "UTF-8")
                + "&h="+ HmacUtils.hmacSha256Hex(hmacKey, url);
    }

そうすると、リダイレクト用のURLを作ることができます。

/redirect?u=http%3A%2F%2Fwww.yahoo.co.jp%2F&h=55fba8d6d44d8f2bd553cd76e018a06318860d5b748a4995292602ad615422de

リダイレクト用のアプリケーションは、それを突き合わせる以下のような感じになります。

public class RedirectServlet extends HttpServlet{
    private String key;
    private String confirmPath;

    public void init() throws ServletException {
        ServletConfig config = getServletConfig();
        key = config.getInitParameter("key");
        if (key == null) {
            key = UUID.randomUUID().toString();
        }
        confirmPath = config.getInitParameter("confirmPath");
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        URL url;

        String userHash = request.getParameter("h");
        try {
            String u = request.getParameter("u");
            url = new URL(u);
        } catch (Exception e) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }
        try {
            String digestHex = HmacUtils.hmacSha256Hex(key, url.toString());
            if (userHash != null && userHash.equals(digestHex)) {
                response.sendRedirect(url.toString());
                return;
            } else if (confirmPath != null) {
                RequestDispatcher dispatcher = request.getRequestDispatcher(confirmPath);
                dispatcher.forward(request, response);
            } else {
                response.sendError(HttpServletResponse.SC_FORBIDDEN);
            }
        } catch (Exception e) {
            log("something wrong", e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
    }

}

これで、Facebookのl.phpと同じような機能を作ることができます。

まとめ

HMACによる改ざん検知は、Javaでは簡単に使えて、いろいろ役に立ちます1

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした