CodeIgniter 3のライセンスがMITライセンスに変更され、いわゆるライセンス問題は完全に解消

CodeIgniter 3.0がMITライセンスでリリースされることが決まりました!

GitHubのリポジトリは、すでにMITライセンスに変更されています。

CodeIgniter 3.0はOSL 3.0というあまり聞いたことのないオープンソースライセンスでリリースされることが開発元のEllisLabにより決められていました。

OSL 3.0へのライセンス変更の詳しい経緯に興味がある方は、

を参照して下さい。

OSL 3.0は、GPLと互換性がないこと、ライセンスがマイナーで解説などの情報が少ないなどライセンスを理解するのが困難なこと、コピーレフトなライセンスであることなどから、一部のユーザからは歓迎されていませんでした。

しかし、EllisLabがビジネス上の判断からCodeIgniterを手放すことになり、オーナーがブリティッシュコロンビア工科大学(BCIT)に変わりました。

今回、BCITはアカデミックな世界の存在であり、EllisLabとは違いよりオープンで寛容なライセンスが望ましいということで、CodeIgniter 3.0をMITライセンスでリリースすることを決定しました。

ライセンス変更に関するタイムライン

日付(日本時間) 出来事
2013/07/10 EllisLabがCodeIgniterの新しいオーナーを探すことを発表
2014/10/06 EllisLabがCodeIgniterの新しいオーナーがブリティッシュコロンビア工科大学(BCIT)に決まったことを発表
2014/10/14 BCITのCodeIgniter Project LeadであるJames ParryがEllisLabのフォーラムにThe Future of CodeIgniterを投稿。ユーザからのライセンスがOSLになることへの不満も投稿される
2014/10/23 BCIT運営の新しいフォーラムにThe CI 3.0 licenseが投稿されライセンスの変更が要望される
2014/10/28 Project LeadであるJames ParryがCodeIgniter 3 Will be Released Under the MIT Licenseを投稿し、MITライセンスへの変更を公表

ということで、いわゆる「CodeIgniterのライセンス問題」は完全に解消しました。

なお、CodeIgniter 2.xまでは、今まで同様、EllisLabのCodeIgniterライセンスのままです。このライセンスはOSIに認定されたオープンソースライセンスではなく、また、一般的にGPLと非互換であると理解されています。

関連

Tags: codeigniter

PHPでCSP(Content Security Policy)を導入してXSS対策を強化してみよう

PHPで簡単にCSPを導入するためのライブラリを作成してみました。

GitHubリポジトリのスクリーンショット

既存サイトへの影響を最小限にしてCSPが導入できることを目的としています。

基本的にCSP nonce-sourceを使い、nonceのないscriptタグは実行しないようにすることでXSS対策を強化します。

このライブラリの仕様としては、CSP nonce-sourceに対応していると思われる指定ブラウザに対してのみCSPヘッダを出力します。現状、ChromeとFirefoxのみが指定されています。

なお、CSP nonce-sourceに対応したChromeのバージョンがわからないので、確認できたバージョン37以上としてます。

CSPについて

CSPについてよく知らない方は以下のスライドなどをご覧下さい。

このライブラリの使い方

Composerで「kenjis/csp」をインストールするか、GitHubからcloneするなり、Zipファイルを取得してください。

$ git clone https://github.com/kenjis/php-csp-nonce-source.git
$ cd php-csp-nonce-source
$ composer install

使い方のサンプルは以下の通りです。

index.php

<?php
require __DIR__ . '/bootstrap.php';
Csp::sendHeader();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sample of CSP nonce-source</title>
</head>
<body>

<script type="text/javascript" nonce="<?= Csp::getNonce() ?>">
    alert('This works!');
</script>

<script type="text/javascript">
    alert('This does not work!');
</script>

</body>
</html>

Csp::sendHeader();でCSPヘッダが出力されます。

標準では

Content-Security-Policy: script-src 'nonce-$RANDOM'; report-uri /csp-report.php

が出力されますので、nonce属性のないscriptタグは(CSP nonce-source対応ブラウザでは)実行されなくなります。

Csp::getNonce();でnonceの値を取得します。

既存サイトでは、CSPヘッダが出力されるようにして、すべてのscriptタグにnonce属性を追加すれば完了です。

CSP違反レポートが、csp-report.logとして記録されますので参考にしてください。

ただし、現状Firefoxの報告はちょっとおかしいことがあるようです。違反でないものも報告されることがあります。でも、ChromeよりFirefoxのレポートの方が詳しいのでわかりやすいです。

また、CSPには実際にブラウザにポリシーを反映させずに違反を報告させるだけのReport Onlyモードがあります。本番サイトをReport Onlyモードで稼働させれば、CSPを実際に適用する前に検証することができます(後述)。

FuelPHPに導入してみる

サンプルとしてFuelPHPでCSPを導入してみます。

kenjis/cspのインストール

まず、FuelPHP 1.7.xをインストールします。

$ composer create-project fuel/fuel:dev-1.7/master fuel-csp

次にkenjis/cspをインストールします。

$ cd fuel-csp
$ composer require kenjis/csp

アプリケーションブートストラップに以下を追加します。

--- a/fuel/app/bootstrap.php
+++ b/fuel/app/bootstrap.php
@@ -2,6 +2,7 @@
 // Bootstrap the framework DO NOT edit this
 require COREPATH.'bootstrap.php';

+class_alias('Kenjis\Csp\CspStaticProxy', 'Csp');

 Autoloader::add_classes(array(
    // Add classes you want to override here

CSP違反レポートを受信するスクリプトをWeb公開領域にコピーし、

$ cp fuel/vendor/kenjis/csp/csp-report.php public/

パスなどを調整します。きちんとしたい場合は、csp-report.phpに相当するコントローラを作成してください。

--- a/public/csp-report.php
+++ b/public/csp-report.php
@@ -1,6 +1,6 @@
 <?php

-require __DIR__ . '/bootstrap.php';
+require __DIR__ . '/../fuel/vendor/autoload.php';

 use Kenjis\Csp\Logger\File;
 use Kenjis\Csp\CspReport;
@@ -12,7 +12,7 @@ if (! $post) {
     exit;
 }

-$logfile = __DIR__ . '/csp-report.log';
+$logfile = __DIR__ . '/../fuel/app/logs/csp-report.log';
 $logger = new File($logfile);
 $report = new CspReport($logger);
 $report->process($post);

CSPを使ってみる

Baseコントローラを作成し、CSPを使うページではBaseコントローラを継承することにします。全ページでCSPヘッダが同一なら、bootstrap.phpにCsp::sendHeader();を追加する方法も考えられます。

fuel/app/controller/base.php

<?php

class Controller_Base extends Controller
{
    public function before()
    {
        Csp::sendHeader();
    }
}

Controller_Baseを継承してコントローラを作成します。

fuel/app/controller/csp.php

<?php

class Controller_Csp extends Controller_Base
{
    public function action_index()
    {
        return Response::forge(View::forge('csp/index'));
    }
}

これで、このページではCSPヘッダが出力されます。

それでは、ビューを作成します。

fuel/app/view/csp/index.php

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>CSPのサンプル</title>
</head>
<body>

<script type="text/javascript" nonce="<?= Csp::getNonce() ?>">
    alert('これは実行されます。');
</script>

<script type="text/javascript">
    alert('これは実行されません。');
</script>

</body>
</html>

すべてのscriptタグにnonce="<?= Csp::getNonce() ?>"を追加します。

これで完了です。

Report Onlyにしてみる

BaseコントローラにCsp::setReportOnly();を追加します。

fuel/app/controller/base.php

<?php

class Controller_Base extends Controller
{
    public function before()
    {
        Csp::setReportOnly();
        Csp::sendHeader();
    }
}

これで違反の報告のみになります。

ポリシーを追加する

ポリシーを追加してキツくすることもできます。

例えば、デフォルトのポリシーを「外部オリジンからのすべてのリソースを拒否」にするには、以下のようにポリシーを追加設定します。

fuel/app/controller/base.php

<?php

class Controller_Base extends Controller
{
    public function before()
    {
        Csp::addPolicy('default-src', 'self');
//        Csp::setReportOnly();
        Csp::sendHeader();
    }
}

これで、例えば、WelcomeコントローラにCSPを適用します。

--- a/fuel/app/classes/controller/welcome.php
+++ b/fuel/app/classes/controller/welcome.php
@@ -19,7 +19,7 @@
  * @package  app
  * @extends  Controller
  */
-class Controller_Welcome extends Controller
+class Controller_Welcome extends Controller_Base
 {

    /**

この状態でトップページにアクセスすると、インラインのstyleタグも無効になりWelcomeページの頭のFuelPHPのロゴがでなくなります。

FuelPHP Welcomeページのスクリーンショット(インラインstyle禁止)

ちなみに通常のWelcomeページは以下です。

FuelPHP Welcomeページのスクリーンショット(通常)

レポートのログファイルには以下のように記録されます。

fuel/app/logs/csp-report.log

{
    "csp-report": {
        "blocked-uri": "self",
        "document-uri": "http://localhost:8000/",
        "line-number": 7,
        "original-policy": "script-src 'nonce-2LP+8osSXUq97nxHbELPkg=='; report-uri http://localhost:8000/csp-report.php; default-src http://localhost:8000",
        "referrer": "",
        "script-sample": "\n\t\t#logo{\n\t\t\tdisplay: block;\n\t\t\tbackgrou...",
        "source-file": "http://localhost:8000/",
        "violated-directive": ""
    },
    "date": "2014-10-29 23:38:57",
    "headers": {
        "Host": "localhost:8000",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0",
        "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",
        "DNT": "1",
        "Content-Length": "391",
        "Content-Type": "application/json",
        "Connection": "keep-alive"
    }
}

参考

Tags: php, xss, csp, security, fuelphp

CSP (Content Security Policy) nonce-sourceについて調べてみた

CSP nonce-sourceとは?

Content Security Policy (CSP) は、クロスサイトスクリプティング (XSS) やデータインジェクション攻撃を含む、よく知られた種類の攻撃を検出して軽減する、セキュリティの追加レイヤーです。これらの攻撃手法は、データ窃盗からサイト改変、マルウェア感染まで、すべてに使用されます。 https://developer.mozilla.org/ja/docs/Security/CSP より。

XSSに関して簡単に言うと、実行できるJavaScriptを制限して、外部からスクリプトが注入されてもブラウザが実行しないことでXSSを防御する機能ということになります。

例えば、自分のサーバ上のjsファイルからのみのscriptを実行するように指定すれば、外部からスクリプトを挿入されても実行はされず安全になります。

しかし、インラインのJavaScriptを一切禁止してしまうと色々と面倒です。

そこで、実行してよいscriptタグにはnonce属性でリクエストごとにワンタイムな「ランダムな文字列」を指定し、その値をCSPヘッダに指定するというのが、nonce-sourceです。CSP 1.1で導入されました。

例えば、HTTPレスポンスヘッダ(CSPヘッダ)で

Content-Security-Policy: script-src 'nonce-sXXD/nluT6AqhuVwL0IJqA=='

と指定します。sXXD/nluT6AqhuVwL0IJqA==がnonceの値でbase64値です。この場合、HTMLの中に以下の2つのscriptタグがあると、

<script type="text/javascript" nonce="sXXD/nluT6AqhuVwL0IJqA==">
    // ここはnonceが正しいので実行される
    alert('This works!');
</script>

<script type="text/javascript">
    // ここはnonceがない(nonceが不正)ので実行されない
    alert('This does not work!');
</script>

ということになります。

もともとHTMLソースにある正当なscriptタグはnonceを指定することで実行されますが、外部から不正に注入されたscriptには正当なnonceがないので実行されない、というわけです。

なかなかよさそうですが、実際に導入するにはブラウザの対応状況などを確認する必要があります。ということで調べてみました。

ブラウザの対応状況の検証結果

script-src nonce

CSPのscript-srcにnonceのみを指定した場合です。

Content-Security-Policy: script-src 'nonce-$RANDOM'
OS ブラウザ バージョン nonce付きscriptタグ nonceなしscriptタグ 判定
Windows Firefox 33.0.1 実行 実行されず
Linux Firefox 33.0 実行 実行されず
Mac Firefox 33.0 実行 実行されず
Windows Firefox 23.0.1 実行 実行 ×
Windows Firefox 22.0 実行 実行 ×
Linux Chrome 38.0.2125.104 実行 実行されず
Mac Chrome 38.0.2125.104 実行 実行されず
Linux Chromium 37.0.2062.120 実行 実行されず
Linux Opera 12.16 実行 実行 ×
Mac Safari 8.0 (10600.1.25) 実行されず 実行されず ×
Windows IE 11.0 実行 実行 ×

Firefox 33、Chrome(Chromium)37/38は正常にnonce-sourceをサポートしています。

Opera、IEはnonce-sourceをサポートしておらず、nonceがないscriptも実行されます。

Safariはnonce-sourceをサポートしてないだけでなく、scriptが全く実行されなくなってしまっています。SafariはCSP 1.0には対応しているため、このような結果になるようです。

このCSPヘッダでは、CSP 1.0のみ対応のブラウザでscriptが全く実行されなくなる不具合が生じてしまうようです。

script-src unsafe-inline and nonce

フォールバックのために、CSPのscript-srcにunsafe-inlineとnonceの両方を指定した場合です。

Content-Security-Policy: script-src 'unsafe-inline' 'nonce-$RANDOM'
OS ブラウザ バージョン nonce付きscriptタグ nonceなしscriptタグ 判定
Windows Firefox 33.0.1 実行 実行 ×
Linux Firefox 33.0 実行 実行 ×
Mac Firefox 33.0 実行 実行 ×
Windows Firefox 23.0.1 実行 実行 ×
Windows Firefox 22.0 実行 実行 ×
Linux Chrome 38.0.2125.104 実行 実行されず
Mac Chrome 38.0.2125.104 実行 実行されず
Linux Chromium 37.0.2062.120 実行 実行されず
Linux Opera 12.16 実行 実行 ×
Mac Safari 8.0 (10600.1.25) 実行 実行 ×
Windows IE 11.0 実行 実行 ×

Chrome(Chromium)はnonceのみの場合と同じですが、Firefox 33ではnonceがないscriptも実行されてしまっています。これはFirefoxのバグでしょうか?

Firefox 22、Opera、Safari、IEはnonce-sourceをサポートしていないため、すべてのscriptが実行されています。

このCSPヘッダでは、CSP 1.0対応のSafariでもscriptが実行されなくなってしまう不具合はなくなりましたが、nounce-sourceに対応しているはずのFirefoxで保護が無効になってしまっています。

調査結果のまとめ

nonce-sourceに対応しているブラウザでは保護が働き、未対応のブラウザでは今までどおりscriptがすべて実行されればよいのですが、

  • Content-Security-Policy: script-src 'nonce-$RANDOM'のみだと、CSP 1.0対応のSafariでscriptが全く実行されなくなる不具合が生じる
  • Content-Security-Policy: script-src 'unsafe-inline' 'nonce-$RANDOM'とすると対応しているはずのFirefoxで保護が無効になる

という状況です。なかなかうまくいきませんね。

といくことで、ChromeとFirefoxの対応バージョンにのみ、CSPヘッダを出力するのが現実的かなと思います。

nonce-sourceに対応したChromeのバージョンっていくつなんでしょう?わかる方いましたら、お教え願えるとありがたいです。

Firefoxは31のようなのですが。

ブラウザの対応状況の検証方法

検証と実装のためのリポジトリをGitHubに用意しました。

ソースコードをインストールします。

$ git clone https://github.com/kenjis/php-csp-nonce-source.git
$ cd php-csp-nonce-source
$ composer install

PHPのビルトインWebサーバを起動します。

$ php -S localhost:8000

http://localhost:8000/check/ にアクセスし、順にリンクをクリックします。

nonce付きのscriptタグが実行されると「This works!」とアラートが出ます。このアラートが出るのは正常です。

nonceなしのscriptタグが実行されると「This does not work!」とアラートが出ます。このアラートが出るということは、ブラウザがnonce-sourceに対応していないということになります。

参考

Tags: php, csp, security, xss