vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

Angularのセキュリティ対策について調べてみる その4

はじめに

続きです。

特定のURLでCSRF(XSRF)対策を無効にする方法、ドキュメントのCross-site script inclusion (XSSI)について追いかけてみました。

特定のURLでCSRF対策を無効にする

前回は全ページでログインしていないとPostリクエストが送れない状態でしたが、
これでは少し不便ですね。

基本的にCSRFの対策はアカウントのパスワード変更など、ログインした状態で行う処理に対して実行するもの、
ということを考えると、例えばログインしていなくても送信したい情報がある場合、
そのページではCSRFを無効にして未ログイン状態でもPostリクエストを送信できるようにする必要があります。

http.csrf().disable()を使う(失敗)

下記のように「http.csrf().disable()」を使ってCSRF対策を無効にしようとすると、 全ページで無効になったり、「http.csrf().disable()」が無視されてしまいます。

WebSecurityConfig.java

〜省略〜
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    〜省略〜
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().and()
                .authorizeRequests()
                .antMatchers("/menulist").authenticated()
                .and().formLogin()
                .and().csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and().exceptionHandling()
                .accessDeniedPage("/accessdenied.html");

        http
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .and().csrf()
                .disable();
    }
    
}

http.csrf().ignoringAntMatchers()

じゃあどうするか、というと、「http.csrf().ignoringAntMatchers()」を使用します。

WebSecurityConfig.java

〜省略〜
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    〜省略〜
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().and()
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/menulist").authenticated()
                .and().formLogin()
                .and().csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and().exceptionHandling()
                .accessDeniedPage("/accessdenied.html");

        http
                .csrf()
                .ignoringAntMatchers("/postsample");
    }
    
}

ここで注意が必要なのは、「ignoringAntMatchers()」で指定するURLはページのURLではなくPostリクエストの送信先のURLであるということです。

そのため、CSRFを有効にするページとそうでないページとでPostリクエストの送信先が一緒になっていると、
両方でログインを求められたりCSRF対策が無効になってしまったりします。

まぁ適当にコピペしているのでもなければ、通常そんなことは無いだろうとは思いますがorz

X-XSRF-TOKENについて

CSRF対策用のトークンなどは、Spring boot側でCSRF対策が有効・無効であるかにかかわらず、常に含まれるようです。

f:id:mslGt:20170804005758j:plain

f:id:mslGt:20170804005810j:plain

ただし、トークンの値はログインのタイミングで更新されるため、

  1. ログイン前にCSRF対策を無効にしたPostリクエストを送信する
  2. ログインして、CSRF対策を有効にしたPostリクエストを送信する
  3. ログイン状態のままCSRF対策を無効にしたPostリクエストを送信する

とすると、2と3で同じトークンが渡され、1とは異なる値になっています。

IDの固定化攻撃の対策も自動で行ってくれる、ということですね。すごい!

Cross-site script inclusion (XSSI)

JSONから重要なデータを読み取られる脆弱性、ということですが、
JSONとしてサーバー側から受け取った値がそのままJavascriptとして実行できる場合にのみ発生するようで、
XSSなどと比較すると常に気をつけなければいけない、という訳でもないのかしら。。。?
(すみません。イマイチ内容が理解できていません)

とりあえず、このXSSIを防ぐ方法としてサーバー側で冒頭に「)]}」や「\n(改行コード)」をJSONデータのプレフィックスとして付与するというものがあり、
AngularのHttpClientではそれらのプレフィックスをJSONの解析前に削除する、というのが本項目の内容です。

おわりに

一通りAngularのSecurityのページを眺めてみました。

軽く触っただけのところなど、気になる部分もありますが、
次からはSpring Security側の設定なども含めて、実際に何かWebアプリでも作りつつ試していくことにしたいと思います。

ブログはせっかくここに書き溜めているわけですし(なお質は問わないものとする)、
PCやスマホからメモを残したりスケジュールを追加したりできるようなものを作ってみようかな?
(できるとは言っていない)

参照

CSRF

XSSI