Rubyで正規表現

Ruby正規表現を扱う方法をまとめておく。

doc = "<html>Lorem ipsum dolor sit amet</html>"

# Loremという文字が出現する位置を調べる
puts doc =~ /Lorem/
# => 6
# 逆でもいい
puts /Lorem/ =~ doc
# => 6

# 正規表現に一致する文字列を取得する
if md = doc.match(/<html>(.+)<\/html>/)
    # これも逆でもいい。→ /.../.match(doc)
    puts md[0]
    # => "<html>Lorem ipsum dolor sit amet</html>"
    #  全体と一致する文字列が入る
    puts md[1]
    # => "Lorem ipsum dolor sit amet"
    #  ()内の文字列が入る
end

# 取得したい文字列が複数ある場合は scan を使う
doc2 = "<html>Lorem ipsum dolor sit amet</html><html>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</html>"
# 2つあるhtmlタグ内の文字列を取得したい
sd = doc.scan(/<html>([^<]+)<\/html>/)
# => [["Lorem ipsum dolor sit amet"], ["sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"]]

Null参照エラーを撲滅するために

クイックソートの発明者として知られるアントニー・ホーアは同時に、 プログラマにとっては馴染み深い Null の生みの親でもあるが、 氏は次のような後悔を口にしておられる。

これ(Null)は、後に数え切れない過ち、脆弱性、システムクラッシュを引き起こし、 過去40年間で10億ドル相当の苦痛と損害を引き起こしたとみられる。

そうなのである。 多分、Null参照が原因のバグは全体の1割はある気がする(適当)。

そんなわけで、この忌まわしきNull参照を撲滅するための対策を考えみた。

その1 Nullを返さない

メソッドの戻り値としてNullを返さないようにする。 配列を返して、受け手側でループで処理しよう。 また、どうしても配列の先頭要素を取得してそれを返したい場合は、 Nullの時は空のインスタンスを返そう。 (NullObjectパタンを使ってもいいが全部のオブジェクトに対してこれを定義するのはしんどいので、重要なものだけにするのがよいと思う)

その2 Nullを代入しない

値の初期値にNullを代入しない。 stringの場合は空文字列、数値の場合は0、オブジェクトの場合は空のインスタンス(もしくはNullObject)を設定する。 「= nil」は絶対に認めない!

その3 Swiftを使う

人類は学んだ。Nullを代入できなければ、Null参照など発生しないことを。 Swiftはデフォルトの型でNullの代入ができない。 なので、以下のようなコードはエラーになりコンパイルできない。

var normalStr : String = null
=> エラー

Nullを代入するにはオプショナル型を使わなければならない。

var normalStr : String? = null

ビルド時にオプショナル型の使用を検知するような仕組みを作っておけば、 Null参照が起こる可能性を0にできる。

クロスサイトスクリプティングって何だ?

Wikipediaによると

クロスサイトスクリプティング(英: cross site scripting)とは、 ウェブページの部分をユーザからの入力をそのままエコーバック (オウム返し)することによって生成しているアプリケーションの セキュリティ上の不備を利用して、サイト間を横断して悪意のある スクリプトを注入する攻撃のことをいう。また経緯上、 それを許してしまう脆弱性についても、このように呼ばれている。

とのことらしい。 全然わからんかったので、自分でHTMLを書いてみたらようやく理解できた。

超簡単なXSSのサンプル

入力内容をそのままページに表示するプログラムを書いてみる。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
</head>
<body>
  <p></p>
  <h4><a href="http://google.com">Google</a></h4>
  <ul>
    <li>今日はいい天気</li>
  </ul>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <input type="text" name="name" id="inputed_text" value="">
  <input type="button" name="name" id="btnRegist" value="投稿">
  <script type="text/javascript">
    $(function() {
      $('#btnRegist').on('click', function() {
        var inputed_text = $('#inputed_text').val();
        $('ul').append('<li>'+ inputed_text +'</li>');
      });
    });
  </script>
</body>
</html>

f:id:Turing:20160828213528p:plain

投稿ボタンを押すと入力内容がそのままページに表示される。これはサンプルとしてHTMLだけで書いたが、実際には入力内容はサーバーに保存され、このWebサービスを使う全ユーザが同じ内容を共有できるようになっていると仮定する。

この入力欄に下記のような一文を挿れて投稿してみる。

</li>
<script type="text/javascript">
  $('a').attr('href','http://yahoo.co.jp');
</script>
<li>

するとHtmlはこのようになる。

<html lang="ja"><head>
  <meta charset="utf-8">
</head>
<body>
  <p></p>
  <h4><a href="http://yahoo.co.jp">Google</a></h4>
  <ul>
    <li>今日はいい天気</li>
  <li></li> <script type="text/javascript">   $('a').attr('href','http://yahoo.co.jp'); </script> <li></li></ul>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <input type="text" name="name" id="inputed_text" value="">
  <input type="button" name="name" id="btnRegist" value="投稿">
  <script type="text/javascript">
    $(function() {
      $('#btnRegist').on('click', function() {
        var inputed_text = $('#inputed_text').val();
        $('ul').append('<li>'+ inputed_text +'</li>');
      });
    });
  </script>
</body></html>

ul要素(リスト)の中にscriptが埋め込まれ、Googleのリンク先が Yahoo!JAPANに変わっている。

今回のサンプルはリンク先を変えただけだが、input要素のPostの送信先を改ざんしてクレジットカード番号を抜き取るというようなことが行われているらしい。

対策は?

入力内容に含まれる危ない文字(<とか>とか&やら)をエスケープするのが基本的な対策法。

RubyOnRailsはRails2までは、明示的なエスケープ処理を書く必要があったけどRails3からはエスケープがデフォルトになったんだそう。

Rubyの要点

Rubyを使っていて、自分の理解が浅かったところをまとめてみました。

map,reduce,filter

Lispなどの関数型言語でお馴染みの上記関数をRubyで使う。

map

rubyにもmapメソッドがあります。 実際はcollectというメソッドの別名ですが、mapを使うほうが混乱は少ないかな。

list = (1..10)
list.map{|i| i*2} #listの全要素を2倍します
reduce

これもinjectというメソッドの別名です。

list = (1..10)
list.reduce {|sum,n| sum+n} #すべての要素を足し合わせる
filter(=select)

Haskellなどで使われるfilterメソッドに対応するのはselectというメソッドです。

list = (1..10)
list.select{|n| n % 3 == 0} #3の倍数を抽出する

ブロック

do 〜 end(または{〜})で囲まれた部分。 メソッドの引数として使われる。

mapを実装してみる。

list = (1..10)
# 特異メソッドを使ってlistのインスタンスにmap2を実装
def list.map2(&block)
 new_list = []
 self.each do |i|
  new_list << block.call(i)
 end
 new_list
end
list.map2{|i| i*2}
=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

&blockでブロック引数を受け取っている。
&はブロックをProcオブジェクトに変換するための記号。
(ブロック自体はオブジェクトとして存在できず引数として渡せないのでこのような方法をとるらしい)
ただ、この書き方は冗長である。なぜなら・・
「ブロック引数は仮引数の中で一番最後に渡されなければならない」
という制約があるから。 つまり、引数自体宣言する必要ないんじゃね?ということ。
このためRubyにはyield(イールド)という構文が用意されている。
これを使えばブロック引数の宣言すら必要ない。こんな感じでかけちゃう・・・

# yieldを使って書き直す
def list.map3()
 new_list = []
 self.each do |i|
  new_list << yield(i)
 end
 new_list
end

ただ、yieldを使うと個人的には少し読みにくい気もする。

ASP.NET MVCで簡単なTODO管理アプリを作りました

ASP.NET MVCで簡単なTODOアプリを作ってみました。

ソースコードGitHubにあげています。

https://github.com/nakamurau1/AspMvcReminder

トップ画面
f:id:Turing:20160811143536p:plain

タスク作成画面
f:id:Turing:20160811143550p:plain

タスク編集画面
f:id:Turing:20160811143543p:plain