Webセキュリティの小部屋

Twitter のフォローはこちらから Facebook ページはこちら RSSフィードのご登録はこちらから
公開日:2013年8月3日
最終更新日:2020年8月13日

JSON セキュリティ:Java で Jackson を使う

JSON のセキュリティ対策は、以下の記事に記載した通りですが、これを Java ではサーブレットで実現します。この記事では、JSON セキュリティ対策のサンプルプログラムを提示します。

Java のクラスインスタンスを JSON に変換するのには、オープンソースの Jackson を今回は使用します。

概要

この記事で作成する Web サービスでは、Jackson を使用して Java クラスのインスタンスを JSON に変換します。

クライアントからリクエストを受け取ると、Web サービスは該当するデータを検索して、一致したデータを JSON の形式でクライアントに返します。

呼び出し元のクライアントは、jQuery と prototype.js を使用した HTML を作成します。

Web サービスの作成

GET リクエストでパラメーターを受け付け、JSON で値を返すよう定義します。

・Json.java

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.fasterxml.jackson.databind.ObjectMapper;


public class Json extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    
    //check XMLHttpRequest Header
    String xhr = req.getHeader("X-Requested-With");
    
    if (!("XMLHttpRequest".equals(xhr))) {
      resp.sendError(403); //Forbidden
    }
    
    //Search name
    String name = req.getParameter("name");
    Person person = searchPerson(name, createList());
    
    //Object to JSON
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(person);
    
    //Add Header
    resp.setContentType("application/json; charset=utf-8");
    resp.addHeader("X-Content-Type-Options", "nosniff");
    
    //Response
    PrintWriter out = resp.getWriter();
    out.println(json);
  }
  
  private List<Person> createList() {
    List<Person> list = new ArrayList<Person>();
    
    list.add(new Person("Yamada", 10));
    list.add(new Person("Sato", 20));
    list.add(new Person("Tanaka", 30));
    
    return list;
  }
  
  private Person searchPerson(String name, List<Person> list) {
    Iterator<Person> i = list.iterator();
    
    while(i.hasNext()) {
      Person person = i.next();
      
      if (person.getName().equals(name)) {
        return person;
      }
    }
    
    return null;
  }
}

・Person.java

public class Person {
  private String name;
  
  private int age;

  public Person() {
    
  }
  
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  
  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
  
}

クライアントの作成

Web サービスにリクエストを送信し、レスポンスのデータを表示するクライアントを作成します。レスポンスのデータを表示する際、HTML エスケープしていることに注意してください。

jQuery で作成

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title></title>
  <script src="js/jquery-2.0.3.min.js"></script>
  <script type="text/javascript">
    $.ajax({
      type: "GET",
      url: "/test/json",
      data: 'name=Yamada',
      success: function (data, textStatus, xhr) {

        //HTML escape and append
        $("#person").text(data.name + " " + data.age); 
      }
    });
  </script>
</head>
<body>
  <div id="person"></div>
</body>
</html>

実行結果は、以下のようになります。

Yamada 10

jQuery によって、以下の行がリクエストヘッダーに追加されていることに注意してください。

  • X-Requested-With: XMLHttpRequest

GET http://localhost:8080/test/json?name=Yamada HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36
Referer: http://localhost:8080/test/JsonSample.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ja,en-US;q=0.8,en;q=0.6

以下の2行が、レスポンスヘッダー追加されていることに注意してください。

  • Content-Type: application/json; charset=utf-8
  • X-Content-Type-Options: nosniff

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
Content-Type: application/json;charset=utf-8
Content-Length: 28
Date: Sat, 03 Aug 2013 07:03:51 GMT

prototype.js で作成

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title></title>
  <script src="js/prototype.js"></script>
  <script type="text/javascript">
    new Ajax.Request("/test/json", {
      method: "GET",
      parameters:{name:"Yamada"},
      onSuccess: function (data) {
        //Text to JSON and security check
        var json = data.responseText.evalJSON(true);
        var str = json.name + " " + json.age;
        $("person").update(str.escapeHTML()); //HTML escape and update
      }
    });

  </script>
</head>
<body>
  <div id="person"></div>
</body>
</html>

実行結果は、以下のようになります。

Yamada 10

prototype.js によって、以下の行がリクエストヘッダーに追加されていることに注意してください。

  • X-Requested-With: XMLHttpRequest

GET http://localhost:8080/test/json?name=Yamada HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Accept: text/javascript, text/html, application/xml, text/xml, */*
X-Prototype-Version: 1.7.1
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36
Referer: http://localhost:8080/test/JsonSample2.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ja,en-US;q=0.8,en;q=0.6

以下の2行が、レスポンスヘッダー追加されていることに注意してください。

  • Content-Type: application/json; charset=utf-8
  • X-Content-Type-Options: nosniff

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
Content-Type: application/json;charset=utf-8
Content-Length: 28
Date: Sat, 03 Aug 2013 07:08:51 GMT

参考

Webアプリケーションセキュリティに関する記事は、以下のページにまとまっています。ぜひご確認ください。


スポンサーリンク





カテゴリー:Webアプリケーションセキュリティ対策

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA