home ホーム search 検索 -  login ログイン  | help ヘルプ

find 検索

201 - 210 / 1320    [|<]  [|<]  [<]  21  22  23  24  25  26  27  28  29  30   [>]  [>|][>|]
タイトル/名前 更新者 更新日
技術/Socketプログラミング/Java (Groovy) の Socketプログラミングを strace と Wireshark で覗く msakamoto-sf 2014-02-15 23:04:50
Java/Enumの使い方メモ msakamoto-sf 2014-02-11 19:32:43
日記/2014/02/11/Apache Commons FileUploadのCVE-2014-0050,JVN#14876762の確認(不完全燃焼) msakamoto-sf 2014-02-11 19:31:02
Java/Serializeメモ msakamoto-sf 2014-02-10 21:36:08
Ruby/rubygemsメモ("gem install"するその前にチェックしておきたい項目) msakamoto-sf 2014-02-10 18:31:46
Ruby/rbenv, ruby-buildメモ(2014-02版) msakamoto-sf 2014-02-10 18:04:03
Ruby/Bundlerメモ msakamoto-sf 2014-02-10 17:17:23
Ruby/Web開発メモ(Rack, Sinatra) msakamoto-sf 2014-02-10 17:02:22
技術/HTTP/Cookie, Set-Cookieヘッダにおける記号の扱いのバラつきについて msakamoto-sf 2014-02-08 21:21:16
日記/2014/02/03/JAX-RS 2.0, Jerseyのメモその2 msakamoto-sf 2014-02-03 08:15:32
ソート項目 / ソート順     1ページ 件ずつ表示

技術/Socketプログラミング/Java (Groovy) の Socketプログラミングを strace と Wireshark で覗く  

所有者: msakamoto-sf    作成日: 2014-02-15 22:53:28
カテゴリ: Groovy Java UNIX ネットワーク プログラミング 

JavaのSocketプログラミングでTCP通信を勉強し始めてから10年近く、ずっと気になっていた点として、socket周りのシステムコールとTCPパケットレベルでの挙動観察をしてみようと思います。

(全て表示する)
プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-15 23:04:50
md5:f5cccabe7a4349239ee62fc9af9164b2
sha1:fb7b857b1c9d804f7c9b4b830f715676ad6491f3

Java/Enumの使い方メモ  

所有者: msakamoto-sf    作成日: 2014-02-10 15:37:50
カテゴリ: Java 

Java5から導入されたenumですが、うまく使いこなせるとより分かりやすいプログラムが書けます。
ヒントになりそうなサンプルコードを作ってみましたので、紹介します。(GitHubにTestNGテストコードの形式でアップしてます)

基本的な使い方:

  • https://github.com/msakamoto-sf/javasnack/blob/master/src/test/java/javasnack/testng1/enums/TestEnumBasics.java
    • java.lang.Enum#values() メソッド, valuesOf(String) メソッド, ordinal() メソッドを覚えておくと、enumを柔軟に運用できると思うのでオススメです。
    • コンストラクタをカスタマイズして、複数の値のペアをカプセル化することもできます。"Tuple"っぽいですね。
    • abstractメソッドを定義して、インスタンスごとにoverrideしたり、interfaceを実装することもできます。

EnumをキーとしたCollectionの紹介:

型安全(Type Safe)な定数定義としてのEnumと、その定数値からの逆引き:

enumの使い方はネット上にも色々資料がありますが、"Effective Java"の第二版に、基本からヒントになりそうな応用まで豊富に紹介されてますので、そちらもオススメです。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-11 19:32:43
md5:7d1fa4aa2869779cca0a2ff5bd98cfc1
sha1:fd1b5e6ff3529419a15bb2681473718e41a66c1a

日記/2014/02/11/Apache Commons FileUploadのCVE-2014-0050,JVN#14876762の確認(不完全燃焼)  

所有者: msakamoto-sf    作成日: 2014-02-11 19:24:01
カテゴリ: HTTP Java セキュリティ 

※内容的にはかなり浅くて緩い記事なので、参考程度の扱いでお願いします。また、以下はmsakamoto-sfのプライベートの活動になりますので、所属する組織の公式見解ではありませんのでご了承ください。

こんなのが出てまして、Apache Commons FileUpload については実際に使ったこともありましたので、ちょっと気になりました。

commons-fileuploadについては、 1.3.1 で修正されてるということなので、どんな修正されたのか?↑の参考資料中に、開発者自身のメーリングリスト上での発言がありました。

んー、なんかよく分かんないんですが、バッファサイズのチェックを強化したとかなんとか。
Content-Typeとかboundaryっぽい感じがしますので、関連RFCをざっと復習。

commons-fileupload:

あとよくわかんないのが、JPCERTの方のページに回避策として紹介されてる「Content-Type ヘッダのサイズを 4091 より小さいサイズに制限する」ですね。4091ってどっから出てきたのか謎です。

実際にSVNリポジトリ眺めてみると、r1565143 で、以下のコミットログでそれっぽい修正がされてます。

Fix CVE-2014-0050. Specially crafted input can trigger a DoS if the buffer used by the
<code>MultipartStream</code> is not big enough. When constructing <code>MultipartStream</code>
enforce the requirements for buffer size by throwing an <code>IllegalArgumentException</code>
if the requested buffer size is too small. This prevents the DoS.

このコミットでのメインとなる修正箇所は src/main/java/org/apache/commons/fileupload/MultipartStream.java のコンストラクタ部分です。

修正前:

    public MultipartStream(InputStream input,
            byte[] boundary,
            int bufSize,
            ProgressNotifier pNotifier) {
        this.input = input;
        this.bufSize = bufSize;
        this.buffer = new byte[bufSize];
        this.notifier = pNotifier;

        // We prepend CR/LF to the boundary to chop trailing CR/LF from
        // body-data tokens.
        this.boundary = new byte[boundary.length + BOUNDARY_PREFIX.length];
        this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length;
        this.keepRegion = this.boundary.length;
        System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0,
                BOUNDARY_PREFIX.length);
        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
                boundary.length);

        head = 0;
        tail = 0;
    }

修正後:

    public MultipartStream(InputStream input,
            byte[] boundary,
            int bufSize,
            ProgressNotifier pNotifier) {
        this.input = input;
        this.bufSize = bufSize;
        this.buffer = new byte[bufSize];
        this.notifier = pNotifier;

        // We prepend CR/LF to the boundary to chop trailing CR/LF from
        // body-data tokens.
        this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length;
        if (bufSize < this.boundaryLength + 1) {
            throw new IllegalArgumentException(
                    "The buffer size specified for the MultipartStream is too small");
        }
        this.boundary = new byte[this.boundaryLength];
        this.keepRegion = this.boundary.length;

        System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0,
                BOUNDARY_PREFIX.length);
        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
                boundary.length);

        head = 0;
        tail = 0;
    }

bufSizeで渡されたバッファサイズが、boundaryLength+1より小さいと例外を投げるようになりました。

・・・この修正箇所が、DoSの発生箇所とイコールには思えませんでした。

深くコードを追ってる時間も無いので、もう直接 1.3 版と 1.3.1 版で実際に使って比べてみます。

とりあえず動けば良いので、Web上のサンプルを切り貼りしてこんなServlet作ってみました。

public class FileUploadSampleServlet extends HttpServlet {
 
    private static final long serialVersionUID = 7896611580723129112L;
 
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(1024 * 1024 * 1024);
        ServletContext servletContext = this.getServletConfig()
                .getServletContext();
        File repository = (File) servletContext
                .getAttribute("javax.servlet.context.tempdir");
        factory.setRepository(repository);
 
        ServletFileUpload upload = new ServletFileUpload(factory);
 
        upload.setSizeMax(1024 * 1024 * 1024);
 
        try {
            List<FileItem> items = upload.parseRequest(req);
            Iterator<FileItem> iter = items.iterator();
            while (iter.hasNext()) {
                FileItem item = iter.next();
 
                if (item.isFormField()) {
                    String name = item.getFieldName();
                    String value = item.getString();
                    System.out.println("[" + name + "]=[" + value + "]");
                } else {
                    String fieldName = item.getFieldName();
                    String fileName = item.getName();
                    String contentType = item.getContentType();
                    boolean isInMemory = item.isInMemory();
                    long sizeInBytes = item.getSize();
                    byte[] data = item.get();
                    System.out.println("fieldName=" + fieldName);
                    System.out.println("fileName=" + fileName);
                    System.out.println("contentType=" + contentType);
                    System.out.println("isInMemory=" + isInMemory);
                    System.out.println("sizeInBytes=" + sizeInBytes);
                    System.out.println("length=" + data.length);
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
 
        resp.setContentType("text/html; charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.println("uploaded.");
    }
 
}

はい。で、commons-fileuploadの1.3で、動かしてみます。こんなリクエストをBurpとかお好みのHTTP Proxyソフトで組み立てて送ってあげます。

POST /(サンプルServletのpath) HTTP/1.1
Host: xxxxx
User-Agent: yyyyy
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cache-Control: max-age=0
Content-Type: multipart/form-data; boundary=BOUNDARYABCABC
Content-Length: 2909

--BOUNDARYABCABC
Content-Disposition: form-data; name="t1"

abc
--BOUNDARYABCABC
Content-Disposition: form-data; name="f1"; filename="corkboard.txt"
Content-Type: text/plain

abcdefg
--BOUNDARYABCABC--

ちゃんと受信できれば正常動作確認OKです。

ここで 1.3 版で、"BOUNDARYABCABC" の部分を 4091 バイトの長さの文字列にして送信すると、これは正常に動きます。
ところが、4092 バイトの長さにして送ると、リクエストが返ってきません。
どうやら、org.apache.commons.fileupload.util.Streams#copy() の中のread系の処理で待ちが発生しているらしく、Threadが解放されません。何回も送りつけるとその分だけThreadが増えていってしまい、リソースが枯渇します。

これが 1.3.1 版になると、以下の様な例外が発生します。エラーとはなりますが、処理は進みますのでThreadは開放され、リソースが枯渇しなくなります。

org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: The boundary specified in the Content-type header is too long
	at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:997)
	at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:310)
	at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:334)
	at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:115)
	at net.glamenvseptzen.cve20140050.FileUploadSampleServlet.doPost(FileUploadSampleServlet.java:40)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.IllegalArgumentException: The buffer size specified for the MultipartStream is too small
	at org.apache.commons.fileupload.MultipartStream.<init>(MultipartStream.java:338)
	at org.apache.commons.fileupload.MultipartStream.<init>(MultipartStream.java:367)
	at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:995)
	... 22 more
Caused by:
java.lang.IllegalArgumentException: The buffer size specified for the MultipartStream is too small
	at org.apache.commons.fileupload.MultipartStream.<init>(MultipartStream.java:338)
	at org.apache.commons.fileupload.MultipartStream.<init>(MultipartStream.java:367)
	at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:995)
	at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:310)
	at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:334)
	at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:115)
	at net.glamenvseptzen.cve20140050.FileUploadSampleServlet.doPost(FileUploadSampleServlet.java:40)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:722)

さて、挙動の変化は確認できましたので、あとは「4091バイト」です。
※DoSが実際に発生する処理の特定までは今回はタイムアップなので諦めます。なので「不完全燃焼」です。

サンプルコードみたいに普通の流れでmultipartを処理するとき、MultipartStreamのコンストラクタは以下が使われました。

   public MultipartStream(InputStream input,
           byte[] boundary) {
       this(input, boundary, DEFAULT_BUFSIZE, null);
   }

この "DEFAULT_BUFSIZE" というのが、4096 に設定されています。委譲されたコンストラクタの方では、boundaryLengthの計算で以下のコードを使ってます。

       this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length;

BOUNDARY_PREFIXというのは、CR + LF + "--" の4バイトです。
つまり、4091というのはboundaryLengthが 4091 + 4 で 4095 になる境界値となるわけで、いかにも怪しそうです。

コードの深追いはタイムアップでやりたくないので、このへんで止めておきますが、バッファサイズ周りのズレが原因で、どこかでずっとread待ちになってしまい、処理が止まってしまったのが原因のようです。
そこで、コンストラクタの段階で不正なバッファサイズが指定されたら例外を発生させ、read待ちにならないような修正がなされたようです。

対策ですが、commons-fileuploadを単体で使っているプロジェクトであれば、1.3.1にアップデートするのが良いと思います。
もちろん、commons-fileuploadを使っていないプロジェクト or Tomcat7 以降(=Servlet 3.0以降) でも @MultipartConfig を使っていない箇所については対策はそもそも不要かなと・・・。まさか@MultipartConfigを使っていても使ってなくても動いてしまったりは・・・しないですよね・・・(未確認)。

アップデートできないなどの場合は、JPCERTの回避策にあるように、HTTPリクエストのContent-Typeをチェックしてboundaryが4091バイト以下になるよう制限を加えることになるでしょう。具体的にはリクエストのContent-Typeをチェックしてboundaryが4092バイト以上ならそこで異常終了させてFilterChainをそれ以上動かさない、ようなServletFilterを追加して、multipart処理を行うServletが動く前にそのFilterを通すように修正する、というのが思い浮かびました。

IP制限つけてログインセッションチェック必須の、社内専用ツールの場合などは、攻撃者となりうるのが著しく範囲が狭まるような状況なので、特に修正せずリスクを受け入れる、というような判断をするのもあり得ると思います。

DoS発生箇所の特定とロジックの解説まで踏み込めなかったので不完全燃焼ですが、今回は以上です。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-11 19:31:02
md5:4c60438964a97b8416f243543cdb2f7f
sha1:9856a85affccca7835a7d796a4a2a306ff8f598b

Java/Serializeメモ  

所有者: msakamoto-sf    作成日: 2014-02-10 21:34:26
カテゴリ: Java 

JavaのSerializeについて勉強してみようと思い、簡単なサンプルコードで実験してみました。
https://github.com/msakamoto-sf/javasnack/tree/master/src/test/java/javasnack/testng1/ser

実務に使うとなると、デフォルトコンストラクタやtransientなど、色々注意すべき事項が多そうです。Effective Javaにも詳しい解説があるようですので、そちらをまず参考にしたいと思います。

他、参考:

Web開発で自分が前から気になってたのは、Tomcatのcluster構成で、セッション情報を共有する場合に、セッションに設定できるオブジェクトにはどんな制限があるか?でした。
Tomcatの公式ドキュメントを見ると、 "All your session attributes must implement java.io.Serializable" とありますので、やっぱりSerializeされて処理されてるんだと思いました。:
http://tomcat.apache.org/tomcat-6.0-doc/cluster-howto.html



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-10 21:36:08
md5:5761063907fc5d98b2f3e18d05dadb64
sha1:f1eb22380e219c22fbb0ed8553a534c80b8a0f98

Ruby/rubygemsメモ("gem install"するその前にチェックしておきたい項目)  

所有者: msakamoto-sf    作成日: 2014-02-10 18:30:58
カテゴリ: Ruby 

rubygemsエコシステム:

"gem install" するその前にチェックしておきたい項目

実行環境を調べて、 本当に現在の環境のgemコマンドとインストール先で良いか確認を推奨。

$ gem environment

確認せずに、うっかり gem install するとこんなトラブルに遭遇します。

  • Linuxディストリビューションのパッケージでインストールされたgemとバージョンが衝突して泣く。
  • Rails3で開発していて、途中からRails4での開発も並行するようになり、バージョンや依存ライブラリが衝突して泣く。
  • あるアプリの新規開発でgem installやgem updateしたら、別のアプリの依存関係やバージョン依存に影響が出てしまい、動かなくなり、泣く。

以下の点を十分吟味し、必要に応じて rbenv + ruby-build(Ruby/rbenv, ruby-buildメモ(2014-02版)) や Bundler (Ruby/Bundlerメモ) を導入して、適切な場所にインストールします。

  1. 現在PATHに通っているgemがどこ由来(ディストリビューションのパッケージ / brew / rvm / rbenv + ruby-build)か。
  2. もし他のアプリが同じライブラリの別バージョンにロックインされても影響しないか。
  3. nativeビルド(コンパイル)が必要なgemを導入してコンパイルエラーが発生した状況を想定して、そうしたトラブルに対処出来るだけのノウハウや時間リソースを確保できているか。
  4. 開発するアプリケーションのライフサイクル的に、本当にそこで/そのバージョンで/あるいは、そのライブラリが本当に妥当か。

参考

GEM_HOME, RUBYLIB 環境変数の調整

※GEM_HOMEはgemの「インストール先ディレクトリ」の設定。GEM_PATHは、gemの「探索対象ディレクトリ」の設定。そのため、GEM_HOMEは一つしか設定しないが、GEM_PATHはOSのPATH分割文字列を使って複数のインストール先を指定できる、と理解してます。(2014-02現在の認識。間違ってたらすみません、指摘してもらえれば随時修正します)



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-10 18:31:46
md5:39db526963e9925e166e1e3c33cc60dd
sha1:baeb5f0e727ed98dfc3a92998a522504a6452e5b

Ruby/rbenv, ruby-buildメモ(2014-02版)  

所有者: msakamoto-sf    作成日: 2014-02-10 18:01:54
カテゴリ: Ruby 

お仕事でちょっとRubyを復習する必要がありました。ディストリビューションがパッケージでインストールするバージョンと衝突すると怖いのですが、2014-02現在ですと rbenv + ruby-build で分離してインストールする手法がメジャーかつ安定してるっぽいです。実際にCentOS6にインストールしてみて、触ってみました。

インストール例:CentOS6(x86_64)

1. 開発ツール入れておく。あとGitも。

# yum groupinstall "Development Tools"
# yum -y install git

2. OSX系の記事読むと、OpenSSLとreadlineの開発用パッケージをbrewでインストールしてる記事多かったので、念のため入れておく。

# yum -y install openssl-devel readline-devel

3. rbenvをGitHubからcloneする。(公式の通り)

$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv

4. 公式にあるようなシェルスクリプト設定を入れ込む。今回は ~/.bashrc に以下の2行を追加でよかった。

export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

5. ログインし直すなどして .bashrc の内容を反映させる。
6. ruby-buildをGitHubからcloneする。(公式の通り)

$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

ruby-buildでインストールできるバージョン一覧を確認:

$ rbenv install -l

1.9系を入れてみる。

$ rbenv install 1.9.3-p484

2.0系を入れてみる。

$ rbenv install 2.0.0-p353

rbenv環境で使うバージョンを指定する。

$ rbenv global 1.9.3-p484
$ cat ~/.rbenv/version
1.9.3-p484

あるディレクトリでのみ、別のバージョンのRubyを使うようrbenvで設定する。これは "rbenv global" の設定を上書きする。

$ mkdir -p work/rbenv_r2.0
$ cd work/rbenv_r2.0
$ rbenv local 2.0.0-p353
$ cat .ruby-version
2.0.0-p353

現在のシェルで使用するRubyバージョンを設定する。これは "rbenv local" の設定を上書きする。

$ rbenv shell 1.9.3-p484

"rbenv shell" の設定を解除する。

$ rbenv shell --unset

参考

rbenv, ruby-build参考:

rvm時代:

rvmからrbenv + ruby-buildへの乗り換え参考:

MacOSX前提:



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-10 18:04:03
md5:0ef8d834681437db1f7be8481dc54852
sha1:e41f3885a7a1dbe2ccf5f3c53091db1f52f7184b

Ruby/Bundlerメモ  

所有者: msakamoto-sf    作成日: 2014-02-10 17:17:08
カテゴリ: Ruby 

Bundler:

アプリケーションが依存するライブラリとバージョンをファイルに記述して管理し、一括でインストールやアップデートを行えるようになる。
また、installコマンドで "--path" オプションを指定することで、システムワイドとは別にインストール先を分離することができる。例えば Rails3/4 それぞれに対応したアプリを同じマシン上で開発することも、"bundle install --path vendor/bundle" とすることでアプリごとに分離することができる。

実際の活用方法参考:



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-10 17:17:23
md5:9ccdb105718de925efba711453546bd8
sha1:654a0230bb0f174f43ab874151d512d538ae9beb

Ruby/Web開発メモ(Rack, Sinatra)  

所有者: msakamoto-sf    作成日: 2014-02-10 17:01:53
カテゴリ: Ruby 

RubyでWebアプリを開発する時に、RackとかSinatraを使うためのメモ。

Rack:

2014-02-10時点での認識:(間違ってたらスミマセン、教えて頂ければ随時修正します)
RubyでWeb開発をする場合、Webサーバ側は幅広い選択肢がある。CGI, FCGI, WEBrick, Mongrelなど。
しかし、HTTPリクエストやレスポンスの処理はWebサーバごとに変わるため、Webサーバに依存した書き方をしてしまうとアプリケーションの移植性が損なわれてしまう。
そこで、Webサーバ間の差異を吸収し、一般的なレベルで抽象化して扱える、中間層としてRackが存在する。
Webアプリケーションや、WebアプリのフレームワークはRackが提供するクラスライブラリや抽象化レイヤーを扱うことで、RackがサポートしているWebサーバであれば移植性を確保できる。
(多分、現実は色々とエッジな処理をしようとするとそうも行かないんだろうけど、一般的なレベルではおおよそ上手く巻き取ってくれてるのでは。でなければここまでメジャーになることはないでしょうし・・・)

Sinatra:

シンプルなWebアプリフレームワークだが、静的ファイルのサポートやテンプレートエンジンもいくつかサポートしていて、小回りが効く。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-10 17:02:22
md5:3d79c0f995a7fdba3ee1504d0f224d7e
sha1:667702b461194721290638743a567f736d215afa

技術/HTTP/Cookie, Set-Cookieヘッダにおける記号の扱いのバラつきについて  

所有者: msakamoto-sf    作成日: 2014-02-08 21:13:53
カテゴリ: HTTP 

お仕事の関係で、HTTPリクエストのCookieヘッダの値はどう解釈されているのか調べてみました。

通常はCookieヘッダの値部分は、空白以外の値で、一般的には余計な記号など入り込まないように言語やライブラリ、フレームワーク、あるいはプログラマが処理してます。
しかし、特殊な要件を満たすため、普段は設定しない記号系の文字もCookieで使う必要がありました。
そこでいくつかのメジャーなWebアプリ実行環境について、実際にCookieに特殊な記号を入れて送ってみて、Webアプリケーション側ではどのように処理されて、見えるようになるのか調べてみました。また、逆に、特殊な記号を入れた値をアプリケーションからCookieとして設定すると、最終的なSet-Cookieでどのようにエンコードやエスケープされるかも確認してみました。

2014-02-08時点での確認状況

言語/プラットフォーム Cookieヘッダの解釈 Set-Cookieでのエンコード
PHP5 URLデコードする setcookie():URLエンコード, setrawcookie():そのまま
Tomcat7 一部記号を除きそのまま 基本そのまま、一部記号が入ると""囲み
Ruby(Rackベース) URLデコードする URLエンコードする
ASP (未検証) (未検証)
ASP.NET (未検証) (未検証)
ASP.NET MVC (未検証) (未検証)
Python(WSGIベース) (未検証) (未検証)
node.js (未検証) (未検証)
Play(Nettyベース) (未検証) (未検証)
(その他) (未検証) (未検証)
  • Cookieのname=valueのvalue部分に、";" や "," がそのまま入ると、いずれもname=valueの区切り文字としてRFCにある文字なので、そこで分割してしまう処理系が多いようです。
  • 記号を含めた値でCookieを発行しようとすると、PHP5とRackの場合は、処理系の方で自動的にURLエンコードしてくれました。Javaの場合は""で囲んでくれました。
    • ただし本記事で確認しているのは記号系の扱いであり、日本語やバイナリデータの場合の挙動までは未確認です。Javaの場合は、アプリケーション側でURLエンコードやBase64エンコードするなど、何らかの対応が必要になるかもしれません。
  • 参考:[Studying HTTP] HTTP Cookies

細かい状況については、以下の個別の詳細確認状況を御覧ください。

(全て表示する)
プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-08 21:21:16
md5:e8f326822994d861db3b210e686d7452
sha1:0cd0b54716b182a6528c60462f4566bc649fab47

日記/2014/02/03/JAX-RS 2.0, Jerseyのメモその2  

所有者: msakamoto-sf    作成日: 2014-02-03 08:07:19
カテゴリ: Java 

multipart アップロード:実装依存らしいが、メジャーなFWならそれぞれなりに対応している。

Security, CSRF対策関連:

CSRF対策についてだが、JavaScriptからヘッダーを付けるようにして、サーバ側でそのヘッダーの有無をチェックする方法がいくつかで紹介されていた。SOPに従えばヘッダーをJavaScriptで操作できるのはSameOriginに限定されるので問題ないだろう、とのこと。
ただ、これはXHR2が登場したため、前提は崩れていると思われる。また、XHR2におけるSOPは主にpreflightと、レスポンスを読めるか否かに関わってきており、リクエストを飛ばすだけであれば可能な状態になっていることは徳丸氏やはせがわようすけ氏からの各種スライド・講演資料などから確認できる。
・・・うーん・・・。

Jerseyでセッションを使うには・・・"@Context" でHttpServletRequestをInjectionするのが王道か。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-02-03 08:15:32
md5:cf2f03adbbe77bce124c92a5c5d91f88
sha1:ce1ac1ca6e67004eac4b66b0ba97320f608a3ed9