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アプリケーションセキュリティに関する記事は、以下のページにまとまっています。ぜひご確認ください。
コメント