Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Tuesday, February 25, 2014

ウェブアプリの「合理的な」セキュリティ対策に関する一考察

※※※ミドルウェアを中心に、ウェブ関連の研究開発に携わっている者による雑文です※※※

ウェブの脆弱性は、ウェブアプリケーションのバグに起因するものと、ウェブブラウザのバグに起因するものの2者に大別することができる。

ウェブアプリケーションを開発/提供する仕事に従事している者には、この前者、すなわち、ウェブアプリケーションのバグに起因する脆弱性を最小限に抑え込むことを求められる注1。

かといって、脆弱性がないことを保障するのは難しい。「ウェブアプリケーションにバグがあっても脆弱性とはならない(あるいは被害が限定される)ような設計」を採用するのが現実的だと考えられる。

OSにおける、プロセス間のメモリ分離やuserIDに基づいたファイルへのアクセス制御を考えてみると、OSがセキュリティを「強制」するため、アプリケーション側で不正なコードが実行されても脆弱性とならない、もしくは、影響を小さく抑え込むことができるようになっていることがわかる。

ウェブ技術における同様の例は数多いが、たとえばXSS脆弱性対策を見ると、


といったものを挙げることができる。また、SQL Injection対策を見ると、


等の手法が知られている。

これらの対策をひとつ選択し、あるいは組み合わせて使うことで、コーディングミスがあったとしても脆弱性が発現しない(もしくは発現する可能性が低い)アプリケーションを実現することができる。

ただ、この種の技術には多かれ少なかれ、アプリケーション側のコードに不自由を強いるという側面がある。

たとえば、Content Security Policyには、インラインの<SCRIPT>タグを実行しづらいという制限がある(1.1で修正見込)し、例として挙げたSQL Injection対策のいずれもが現実的でないウェブアプリケーションも多いだろう。また、SQLにおける条件節の漏れによる情報漏洩のように、本質的に対策が難しい注3問題も存在する。

以上のように、共通モジュール(あるいは下位レイヤ)でアクセス方法を「強制」する仕組みを用いることで、脆弱性への耐性を高めるという情報工学における一般的なアプローチは、ウェブ技術においても有効であり、積極的に使用すべきである注4。一方で、述べたように、今後の発展が期待される分野も存在する注5。



注1: 後者については、一義的にはウェブブラウザベンダーが対応すべき問題である。もちろん、ウェブアプリケーション側で緩和策が実装できるならすれば良いケースもある

注2: 最新のテンプレートエンジン事情を良く知らないので列挙はしません。また、DOM APIベースのアプローチについても本稿では割愛します。

注3: ウェブアプリケーションにおいては、アクセス制限とアクセスを単一のクエリで記述することを求められることが多いため。この点は、ケーパビリティの概念を導入したORMのようなアプローチで解決可能なのかもしれないが…

注4: 「IPA 独立行政法人 情報処理推進機構:安全なウェブサイトの作り方」では、脆弱性を9種類に類型化して説明しているが、そのほとんどは「アプリケーションプログラマがミスをしても問題ない」ような共通コード(ウェブアプリケーションフレームワークやライブラリ等)の使用により回避することが可能であるし、そのような実装が称揚されるべきである

注5: なので、研究課題として面白いと思います

Friday, February 7, 2014

Why asm.js sometimes runs faster than hand-written JavaScript (and the changes in JSX 0.9.77)

I have released an update (version 0.9.77) of JSX - a statically-typed altJS programming language with an optimizing compiler to JavaScript, with the following changes:

  • the definition of int has been changed to strict 32-bit signed integer
  • introduce Promise class in conformance to the ECMAScript 6 draft

The second change should be obvious. Let me explain the reasoning behind the first one.

Background:

Until now, definition of int in JSX has been: a number that is at least possible to represent integers between -231 to 231-1, or may or may not become NaN or +-Infinity.

This was based on our understanding that enforcing integer arithmetic in JavaScript (i.e. using | 0) would lead to slower execution speed. We wanted the int type of JSX to represent some kind of integral numbers without sacrificing execution speed. And the type had been defined as such.

But the advent of asm.js has changed the game. Such enforced integer arithmetic is one of the most common patterns found in JavaScript generated by Emscripten (since it compiles C/C++ code), and it would be natural to expect that existing JavaScript runtimes would optimize against such patterns.

The Benchmark:

So I decided to take time to run a tiny benchmark that compares the execution speed of ordinary arithmetic vs. enforced integer arithmetic on fib-using-int - jsPerf, and the results are interesting.

The benchmark compares three functions calculating Fibonacci numbers using loops.

// original
function fib(n) {
  var value = 1, prev = 1;
  for (var i = 1; i < n; ++i) {
    var t = prev;
    prev = value;
    value += t;
  }
  return value;
}

// core operation is enforced integer arith.
function fib(n) {
  var value = 1, prev = 1;
  for (var i = 1; i < n; ++i) {
    var t = prev;
    prev = value;
    value = (value + t) | 0;                <--- HERE
  }
  return value;
}

// core operation and loop are integer arith.
function fib(n) {
  n = n | 0;                                <--- HERE
  var value = 1, prev = 1;
  for (var i = 1; i < n; i = (i + 1) | 0) { <--- HERE
    var t = prev;
    prev = value;
    value = (value + t) | 0;                <--- HERE
  }
  return value;
}

Looking at the results below (please refer to the benchmark page for the latest numbers) the fact is that code runs about 10% faster on Chrome and Firefox when explicitly specifying an extra operation (i.e. | 0).


This is not a surprise for people with the understanding of how the JIT (just-in-time-compile) engines of the runtimes work. The engines compile arithmetic operations in the original function of the benchmark into integer arithmetics with guards, so that the calculation can be changed to use floating-point operations once the numbers goes out of the 32-bit integer range. But if | 0 is added to the statement it becomes clear that the result of the arithmetic should be a module of 232 and thus that the guards become no longer necessary.

The Problem and the Solution:

The problem being left is how to write code that takes benefit from such optimizations. It is hard to add | 0 all over the source code, and there would be a negative performance impact unless you succeed in marking all of them correctly. It is once again clear that some kind of automated code generator is desirable for JavaScript, and this is the reason why we are happily applying the described change to JSX :-)

To summarize, JSX as of version 0.9.77 supports strict 32-bit integer arithmetic; and it is easy for the users to benefit from the described optimizations within the JavaScript runtimes. It's just a matter of marking some variables as : int. And the results of assignment to the variable as well as additions, subtractions, and multiplication between such variables would be int.


PS. I have also written the Fibonacci calculator in asm.js, but have excluded the numbers from the benchmark since it was too slow. It seems that there exists a non-marginal overhead when calling asm.js code from JavaScript.

Monday, January 27, 2014

JSX - experimental support for NPM

Based on @shibukawa-sans work, I have added experimental support for NPM-based packages in JSX 0.9.75. It is now possible to publish libraries for JSX using NPM (or use such packages from JSX).

A tiny example would be the following:

package.json:
{
  "dependencies": {
    "nodejs.jsx": "~ 0.1.1"
  }
}

hello-npm.jsx:
import "nodejs.jsx/*.jsx";

class _Main {
  static function main(args : string[]) : void {
    fs.appendFileSync("/dev/fd/1", "hello npm!\n");
  }
}

Running npm install would install nodejs.jsx (JSX binding for node.js) which is specified as a dependency in package.json. And when the compiler is executed (e.g. jsx hello-npm.jsx) it would automatically search for the imported files and use them in the node_modules directory.

For the time being, file specified in the main section of package.json is used if the name of a module is an argument to the import statement (e.g. import "npm-module-name"). Or the directory designated by the dependencies/lib section is searched if a file within an npm module is specified (e.g. import "npm-module-name/filename").

If you have any comments / suggestions please file a issue at the GitHub issues page.

Wednesday, December 18, 2013

プログラミング言語における正規表現リテラルの必要性について

Twitterに書いたことのまとめです。

プログラミング言語の仕様の一部として正規表現リテラルを提供することの得失について、JavaScriptを例に説明します。

■より簡潔なコード

言うまでもありませんが、正規表現リテラルを使った方が簡潔なコードになります。
(new RegExp("abc")).exec(s)  // リテラルを使わない場合
/abc/.exec(s)                // リテラルを使った場合
また、正規表現リテラルがない場合は、文字列リテラルとしてのエスケープと正規表現としてのエスケープが二重に必要になる結果、コードの保守性が低下します注1。
new RegExp("\\\\n");  // リテラルを使わない場合
/\\n/                 // リテラルを使った場合

■エラー検出タイミング

正規表現リテラルがない場合、実際にその正規表現が評価されるまで記述エラーを検出することができません。正規表現リテラルがあれば、コンパイル時注2にエラーを検出できるので、開発効率と品質が向上します。
new RegExp("(abc")  // 実行時例外
/(abc/              // コンパイル(起動)時にエラー検出

■実行速度

正規表現リテラルがないと、正規表現を適用する度ごとに、毎回正規表現をコンパイルするコードを書きがちです。これは、実行速度を大幅に悪化させます。正規表現リテラルがあれば、正規表現を言語処理系側でコンパイルして使い回すことができるので、実行速度が向上します。
new RegExp("abc").exec(s) // 実行する度に正規表現がコンパイルされる
/abc/.exec(s)             // 正規表現のコンパイルは実行回数に関係なく1回

また、正規表現に対しては「単純な文字列処理関数より遅そう」という意見を目にすることもありますが、そのような一般化は誤りです注3。例えば、JavaScript処理系における速度比較についてはregexp-indexof・jsPerfをご覧ください。ウェブブラウザによっては、正規表現を使ったほうがString#indexOfよりも高速なのがご確認いただけると思います。

■より単純で強力な文字列API

上記3点より、正規表現の使用を前提とするのであれば、正規表現リテラルを採用した方が言語処理系の利用者の開発効率が向上することは明らかだと思います。

残る問題は、正規表現リテラルを採用することで、そのプログラミング言語はより煩雑で、利用者にとって使いづらいものになってしまわないかという点です。

この点については、以下のトレードオフが存在します。

PythonやPHPのような正規表現の使用を積極的にアフォードしていないプログラミング言語では、多くの文字列処理関数が存在します。利用者は、これらの関数の仕様を記憶するか、あるいは都度ドキュメントを参照することを求められます。

これに対し、JavaScriptやPerlのような正規表現リテラルを提供しているプログラミング言語では、文字列処理関数の数は比較的少なくなっています。必要な処理は、プログラマが正規表現を使って簡単に書くことができるからです。

また、正規表現を使うことで、例えば以下のような、複数の評価手法を合成した処理を簡単に記述することができます。文字列処理関数を使うアプローチの場合、このような処理をするためには複数の関数を組み合わせざるを得ません。
/^\s*abc/   // 先頭に空白、続いてabc

■まとめ

以上のように、正規表現リテラルを言語仕様に導入すれば、プログラマに正規表現の学習を強いることと引き換えに、より単純で強力な処理系を提供することができます注4。

言語処理系の開発時に正規表現リテラルを採用すべきか否かについて検討すべき論点は、だいたい以上のとおりだと思います。あとは、言語処理系がどのような目的で、どのような開発者に使われるのか、処理系開発者のバランス感覚によって決まる問題ではないでしょうか。


■補遺 (2013/12/19追記):

正規表現リテラル導入の是非は上のとおりですが、文字列処理に正規表現を推奨すべき否か、という論点について、私の考えを補足します。

プログラミング言語仕様の設計という視座にたった場合、文字列処理の手法として、文字列処理関数を推奨するアプローチと正規表現を推奨するアプローチのいずれがより優れているか、という問いに対して一般化できる答えは存在しません。

たとえば、PHP等に存在するtrim関数(文字列の前後の空白を削除)は、同等の正規表現(s.replace(/^\s*(.*)\s*$/, "$1"))よりも簡潔です。文字列処理のうち、頻出するパターンについて、適切な名前をもつ関数を提供することで可読性を向上させるというアプローチは理に適っています。

逆のケースとしては、次のようなものがあります。

文字列処理を実装していると、文字列の末尾から改行文字を1つ(のみ)削除したいこともあれば、末尾の改行文字を全て削除したいこともあります。正規表現を使えば、この種の需要に対応することは簡単です(/\n$/ あるいは /\n*$/)が、これらの需要に対応する文字列処理関数をいちいち言語処理系で提供することは現実的ではありません。

あるいは、電話番号を入力するフォームにおいて適切な文字のみが使われているかチェックするのに適しているのは、文字列関数ではなく正規表現(/^[0-9\-]+$/)でしょう。

このように、正規表現を使うアプローチには、文字列処理関数と比較して、単純な処理においては可読性が劣りがちな一方で、様々なバリエーションがある処理を統一的な手法で記述できるという点では優れているという特徴があります。

注1: この問題は、エスケープシーケンスの衝突を回避できる言語(例: Perl)、raw文字列リテラルが存在する言語(例: Python)では問題になりません
注2: 多くのインタプリタ型処理系の場合は起動時
注3: プログラムのソースコードであれ正規表現であれ、コンパイル後にVMで(場合によっては機械語にコンパイルして)実行される以上、速度差はその変換処理の優劣の問題だと理解すべきです
注4: 正規表現は使い方に制約がなさすぎて嫌、という考え方もあるかと思います

Saturday, December 7, 2013

JavaScriptで高速なコードを書く際の注意点。または私は如何にして心配するのを止めてJSXを作ることにしたか

本日、福岡で開催されたプログラミング言語のパフォーマンスを考えるイベント「ぷろぐぱ」で、「JSX 速さの秘密 - 高速なJavaScriptを書く方法」という演題で講演しました。

JavaScriptで速いコードを書こうとする際に陥りがちな罠を紹介し、それらの問題にJSXではどうやって対処しているか、プログラミング言語設計と最適化機能の実装を説明しました。プログラミング言語設計に興味がある方にとっても、JavaScriptを使ったプログラミングに興味がある方にとっても面白い内容になっているかと思います。


講演中の写真とあわせてご笑覧いただければ。



※本記事はJSX Advent Calendar 2013の一部です。

Monday, December 2, 2013

Benchmarking asm.js using real-world code (zlib.js)

In response to a chatter between Japanese developers on Twitter about how asm.js would perform on web browsers other than Firefox, @y_imaya has written a benchmark between zlib.js that he develops and maintains vs. zlib-asm written by @ukyo by inflating (e.g. decompressing) Canterbury Corpus (a well-known set of files used for benchmarking compressor/decompressors).

His blog post can be found here but I could not hesitate to take my own benchmark on mobile devices since I use zlib.js at work, and may want to switch to zlib-asm if it runs faster than that.

So here are the numbers (his benchmark is ready to run here). The numbers on the charts show the milliseconds that took for decompressing the whole corpus.


First of all, asm.js running on Firefox is clearly the performance winner among all, showing the technical advantage of the approach. On the other hand, the asm.js-version is roughly 2x slower on other web browsers compared to the hand-written JavaScript variant. So for the time being, it seems that using a well-written JavaScript library would be preferable on browsers other than Firefox.

Anyways qudos to @y_imaya and @ukyo for their great work. I hope to see more benchmarks based on code that is actually used, so that we could understand more about the benefits of asm.js.

EDIT: It would be great if someone could add a benchmark of PNaCl running on Chrome as well.

Wednesday, November 27, 2013

Do not allocate Typed Arrays too frequently, or your browser will die OOM

The following code causes the browsers' JavaScript runtime to crash (or allocate gigabytes of memory) when the array length is only around 1MB to 2MB (reproducible on Google Chrome 30.0.1599.101 / Safari 6.1 (8537.71) running on OS X 10.8.5; Mozilla Firefox 25.0.1 does not have the problem).

current length of Uint8Array is <input id="arrlen"> bytes.
<script>
var arr = new Uint8Array(12345);
function doit() {
  for (var i = 0; i < 100; ++i) {
    arr = new Uint8Array(arr.length + (Math.random() * 500 | 0));
  }
  document.getElementById("arrlen").value = arr.length;
}
setInterval(doit, 1);
</script>

test link

My understanding is that historically, this is due to the fact that Typed Arrays were defined outside of the ECMAScript specification and that it was implemented outside of the JavaScript VMs. Memory chunks that are used to store the elements of the arrays are allocated outside of the VM heap, and GC tracks only the reference to the array elements. Thus the pressure against GC is tiny per each allocation even though the pressure against malloc might be high. And the outcome is that malloc gives up well before GC starts to free the typed arrays that are no longer used.

I had thought that the problem had been fixed a while ago, but it still seems to exist. And although I believe that it will be fixed sooner or later I am writing this weblog so that, until then, others who fall into the pitfall can understand the problem.

PS. opened the issue on the Chromium issues tracker.