昨日のクロスサイト”プリンティング”のテクニック、本当ならWebアプリの世界が広がる気が。。で、調べてみるね!と書いたこと報告。
たしかに、IEで、Formタグに書いた内容とファイル名で、ローカルにファイルを書き出せました
(もちろん、セキュリティレベルを一切変えずに!です)。
その方法と、コードを説明しますね。
■方法の概要
・ローカルに、Socketサーバーで、ポート5050番で、以下の機能を持った
サービスを立ち上げる
・POST形式で受け取った内容をもとに、引数
fnameで指定されたファイル名で、
fdataの内容を書き出す
・フォームタグでmethod=POST action="http://127.0.0.1:5050" を指定、
このフォームタグ内に、fname、fdataを用意しておく。
このファイルを保存し、ローカル以外の別のサーバーに置く
・上記ファイルにアクセスし、fname、fdataをいれ、Submitボタンをクリックすると、
ポート5050のサービスが実行され、fnameに指定したファイル名で、
fdataの内容が書き出される。
■ソース
エラー処理とか、日本語化とか、一切抜いて、簡単に書いてあります。
●別のサーバーに置いたHTMLファイル
これなのですが、中身は、こんなかんじ
<html> <head><title>クロスサイトプリンティング応用テスト</title></head> <body> <form method="post" action="http://127.0.0.1:5050"> <input type=text name=fname><BR> <textarea name=fdata> </textarea><BR> <input type=submit value="実行"><BR> </form> </body> |
(上記< > ¥は、本当は半角です)
●ローカルに置くソース
ローカルにおくプログラムは、起動するプログラムと、1セッション分(1スレッド分)のプログラムの2つに分かれます。
だいたいの書き方は、ここと同じです。
<<1.起動するプログラム>>
とくに、起動するプログラムに関して言うと、まったくおなじです。
以下のプログラムをtest.javaとします
import java.io.*; import java.net.*; public class test { /* * メイン処理(呼び出し元) */ public static void main(String[] args) { try { // サーバーを生成 ServerSocket serverSocket = new ServerSocket(5050); while(true) { // ソケットを生成 Socket socket = serverSocket.accept(); TestThread tr1 = new TestThread(); tr1.setSocket(socket); tr1.start(); } } catch(Exception e) { e.printStackTrace(); } } } |
(上記< > ¥は、本当は半角)
<<2.スレッドのプログラム>>
そいつは、こんなかんじ。「処理」のところがちがっていてて、ファイル保存します。
以下のプログラムをTestThread.javaとします
import java.io.*; import java.net.*; public class TestThread extends Thread { Socket socket = null; public void setSocket(Socket socket) { this.socket = socket; } /* * 処理部分 */ public void run() { if ( socket == null ) { return; } try { //-------------------- //受信する //-------------------- InputStream is1 =socket.getInputStream(); InputStreamReader ir1 = new InputStreamReader(is1); BufferedReader br1 = new BufferedReader(ir1); // よみこめるまでまってる while(is1.available() == 0); // 1行読み込む int c; String header = ""; while((c = br1.read()) != -1 ) { header = header + (char)c; if (( header.indexOf("¥n¥n") > 0 ) || ( header.indexOf("¥r¥n¥r¥n") > 0 ) ) { break; } } // データ部分の長さを取得 String[] line = header.split("¥n"); int datalen = -1; for(int i = 0 ; i < line.length; i ++ ) { if ( line[i].indexOf("Content-Length:") >= 0 ) { String lenbuf = line[i].substring("Content-Length:".length()); try{ datalen = Integer.parseInt(lenbuf.trim()); }catch(Exception e){ } } } // データがある場合、データ取得 String data = ""; if ( datalen > 0 ) { char[] datachar = new char[datalen]; br1.read(datachar); StringBuffer databuf = new StringBuffer(); databuf.append(datachar); data = databuf.toString(); } //-------------------- // 処理 //-------------------- // データがある場合、ファイル名、データ取得 String fname=""; String fdata= ""; if ( data.length() > 0 ) { // 改行をカットする data=data.replaceAll("¥r",""); data=data.replaceAll("¥n",""); // ファイル名とデータきりだし String[] dline = data.split("&"); for(int i = 0 ; i < dline.length ; i ++ ) { String[] cell = dline[i].split("="); if ( cell[0].compareTo("fname") == 0 ) { fname = cell[1]; } else if ( cell[0].compareTo("fdata") == 0 ) { fdata = cell[1]; } } } // ファイル書き出し if (fname.length() > 0 ) { try { File f = new File(fname); FileOutputStream fo = new FileOutputStream(f); fo.write(fdata.getBytes()); fo.close(); } catch(Exception e) { } } //-------------------- //送信する //-------------------- OutputStreamWriter ow1 = new OutputStreamWriter(socket.getOutputStream()); BufferedWriter bw1 = new BufferedWriter(ow1); bw1.write("OK"); bw1.flush(); // クローズ bw1.close(); ow1.close(); br1.close(); ir1.close(); } catch(Exception e) { e.printStackTrace(); } } } |
(上記< > ¥は、本当は半角)
■うごかしかた
で、2つのjavaプログラムをコンパイルして、同じフォルダにおいて、
testのクラスを実行すれば
(Eclipseだったら、同じプロジェクトに入れて、testのクラスを指定して
Runすれば)、
プログラムが開始します(しますけど、その時点では、何もおきません、見かけ上)
で、あらかじめ、どっかのサーバーにおいておいた、HTMLファイルをIEで開いて、
上にファイル名、下に書き出しデータを適当に入れて、実行ボタンを
クリックすると、ファイル書き出しします。
だだし、話を簡単にするため、コード変換とかはしてないので、日本語を入れると
日本語では書き出されませんが・・・