Safariのオートコンプリートの不思議な挙動



検証用のコードは[gistに公開してあります](https://gist.github.com/ymrl/9783401)。

普通のログイン画面
---------------

まず、よくある感じの画面でパスワードを保存してみます。


![ログイン画面](http://gyazo.com/cfbd2e5d162a387ee5014b3bd6d96a54.png)

```html
	<form method="post" action="/">
	  <div>
	    <label>
	      username
	      <input type="text" name="username" />
	    </label>
	  </div>
	  <div>
	    <label>
	      password
	      <input type="password" name="password" />
	    </label>
	  </div>
	  <div>
	    <input type="submit" />
	  </div>
	</form>
```

とりあえずユーザー名に `myname@example.com` パスワードに `password` とか入力して送信して、またこのページに戻ってくるとユーザー名とパスワードが自動入力されます。

![情報が自動入力されたログイン画面](http://gyazo.com/0365a55ad607dcdb9d0414fdc3839688.png)

同じサイト内のパスワードフィールドのあるフォーム
-----------------------------------

この状態で同じサイト内の他のパスワードフィールドのあるページに移動してみます。

```html
	<form method="post" action="/" autocomplete="off">
	  <div>
	    <label>
	      a field
	      <input type="text" name="a_field"  autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
    	  another field
	      <input type="text" name="another_field"  autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      a password
	      <input type="password" name="a_password"  autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <input type="submit" />
	  </div>
	</form>
```

![IDとパスワードが自動入力された](http://gyazo.com/760ced2561f649b03257d3640cafbde0.png)

IDとパスワードが自動入力されました。 わざわざ鬱陶しいほどに `autocomplete="off"` と書いたのにとても親切です。どうやらSafariは `type=password` なフィールドを見つけるとそこにパスワードを、一つ前のフィールドにユーザー名を自動入力してくれるようです。

さらに別のフォームに移動してみる
---------------------------

さらにこんどは、フィールドの `name` 属性をすべて `field[]` にしてみます。こうしておくとRailsなどのモダンなフレームワークはパラメーターを配列として受け取れて便利です。

```html
	<form method="post" action="/" autocomplete="off">
	  <div>
	    <label>
	      a field
	      <input type="text" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      another field
	      <input type="text" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      a password
	      <input type="password" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <input type="submit" />
	  </div>
	</form>
```

![パスワードが丸見えになった](http://gyazo.com/74225929b141b7d0b0191aaa91841767.png)

なんと **パスワードが丸見え** です。どうやら、 `name="field[]"` で `type="password"` なフィールドがあるので、「パスワード入れるところがあるから自動入力するぞ、`field[]` っていうフィールドに入れればいいんだぞ」と思ってくれているようです。

たまたま業務でこの挙動を発見したのですが、「***」のようにマスクされて表示されると思って保存した情報が、こんな感じでページを開いた瞬間に見えるようになってしまうのは危険な感じがします。この挙動について、心配になったのでAppleのセキュリティ窓口に問い合わせをしましたが、「同じ名前のフィールドが存在しているのが原因なのでセキュリティ上の問題ではない」と突っ返されました。うん、こんなページを作ってる人が悪いですね。Safariでパスワードを保存している場合はこんなページを作る人と背後の人に気をつけましょう。

Safariのオートコンプリートを抑止する
-------------------------------

Appleさん的には同じ名前のフィールドを作るなということらしいのですが、やっぱり配列として受け取れて便利という利点は捨てるに惜しいものです。また、同一サイト内で複数のパスワードを使わざるを得ないケースもあるので、そういうときにはパスワードの自動入力を切りたくなると思います。

どうやらSafariは `type="password"` なフィールドが2つあれば自動入力の対象とは見なさなくなるようです。具体的にはこんな感じ。

```html
	<form method="post" action="/" autocomplete="off">
	  <div>
	    <label>
	      a field
	      <input type="text" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      another field
	      <input type="text" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      a password
	      <input type="password" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      another password
	      <input type="password" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <input type="submit" />
	  </div>
	</form>
```

そこで、このフィールドを非表示にして `disabled` にすればいいよね、と思ってこんなコードを書いたのですが、しかしこのままでは自動入力が走ってしまいます。

```html
	<form method="post" action="/" autocomplete="off">
	  <input type="password" name="dummy" disabled="disabled" style="display:none"/>
	  <div>
	    <label>
	      a field
	      <input type="text" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      another field
	      <input type="text" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      a password
	      <input type="password" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <input type="submit" />
	  </div>
	</form>
```

どうやら、`type="password"` なフィールドが描画処理をされなければパスワードフィールドとして認識しないようで、縦横幅を0pxや1pxにしてもやはり自動入力されてしまいました。

そこで、最終的に辿り着いたのが「縦横幅2pxで透明なフィールドを置く」という解決策でした。これなら自動入力されないし、ユーザーにもほとんど影響がありません。めんどくさいですね。

```html
	<form method="post" action="/" autocomplete="off">
	  <input type="text" name="dummy_text" 	disabled="disabled" style="width:2px;height:2px;position:absolute;opacity:0"/>
	  <input type="password" name="dummy_password" disabled="disabled" style="width:2px;height:2px;position:absolute;opacity:0"/>
	  <div>
	    <label>
	      a field
	      <input type="text" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      another field
	      <input type="text" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <label>
	      a password
	      <input type="password" name="field[]" autocomplete="off"/>
	    </label>
	  </div>
	  <div>
	    <input type="submit" />
	  </div>
	</form>
```

※ ちなみに、`type="password"` なフィールドを置いただけでは自動入力されてしまうケースがあったので（ちゃんと検証してません）、念のためその前にテキストフィールドも置いています