Python

curlでログオンフォーム認証をしてページへアクセス(csrfにも対策)

Python

以前の記事でcurlの使い方について書きましたが、今回はcurlを実践的に使っていきます。

curlでページアクセスしたい場合、単純なアクセスだけであれば以下のようにするだけで簡単にアクセスできます。

curl https://syachiku.net

ただし、実際にはアクセスしたいページにログオン認証がされており、その認証をクリアしないとアクセスできない場合が多くあります。 社内のシステムにおいても基本的には認証が必要とされているのではないでしょうか。

Pythonを使うと比較的簡単に実装することができるのですが、今回は素のLinuxで実現したいのでcurlを使います。セッション管理の機能などがないので少し手間ですが、できないことはないです。

今回はそのようなログオンのフォーム認証をクリアしながらcurlでアクセスする方法についてまとめました。

最近はほぼ間違いなくログオンで実施されているcsrf対策についてもクリアするようにします。

1. curlでログオン認証をクリアするために利用するオプション

まずは、curlでログオン認証をクリアするために利用するオプションと意味を記載しておきます。 下の方の記事でcurlコマンドで分からない部分があったら参照しながら進めてください。

繰り返しですが、こちらの記事にもまとめている内容となります。

1.1. POSTでのパラメータしてのアクセス(-F)

  • これはログオンなどでよく使うもの
curl -F "user=value1" -F "passwd=value2" http://www.hogehoge.com/logon

1.2. クッキーを指定してアクセスする(-b)

  • 上のcオプションで保存したクッキーファイルを利用してアクセスする場合
$ curl -b <cookie file名> http://www.hogehoge.com/

1.3. リダイレクトも追うように(-L)

  • もしリダイレクトされてもその先のURLを表示します(ログオン認証などでよく使います)
$ curl -L <cookie file名> http://www.hogehoge.com/

1.4. レスポンス関連(-Iと-i)

//レスポンスメッセージのボディのみ
$ curl http://www.hogehoge.com/

// ステータスラインとヘッダのみ(-I)
$ curl -I http://www.hogehoge.com/

//すべてのレスポンスメッセージを表示(-i)
$ curl -i http://www.hogehoge.com/

1.5. 結果をファイルに書き出す(-o)

  • 結果をファイルに書き出します
  • ダウンロードファイルを指定するのを同じオプションです
$ curl http://www.hogehoge.com/ -o <file名>
  • 何も表示させたくない場合(/dev/nulへ送る)
$ curl http://www.hogehoge.com/ -o /dev/null

1.6. 指定した文字列だけを表示する(-w)

  • よくレスポンスコードだけ取得したい場合に利用します
$ curl http://www.hogehoge.com/ -o /dev/null -w  '%{http_code}\n'

1.7. 進捗やエラーを表示しない(-s)

  • シェルスクリプトなどで結果が表示されるのが邪魔な場合に利用する
$ curl -s http://www.hogehoge.com/

1.8. 詳細をログ出力(-vもしくは–verbose)

$ curl -v http://www.hogehoge.com/

2. 今回のログオン認証をクリアする例

今回はコンテナで構築しているローカルPC内にあるgitlabをサンプルとして使います。

なお、インターネット上にあるサイトにアクセスする際には色々と注意してください。

2.1. ログオン認証をクリアするまでの流れ

まずは、ログオン認証をクリアするまでの流れについて確認します。 ログオン認証をクリアしていない場合には、全てログオンページにリダイレクトされます(302)

  1. ログオンページにGETでアクセスしてcookieを受け取る
  2. ログオンページ内のcsrf tokenの値を取得する
  3. 1で得たcookieを添えたうえで再度ログオンページアクセスする。さらにユーザ名やパスワード、csrf tokenなどの値を設定してPOSTでアクセスしてログオン認証を実施する。そして再度cookieを受け取る
  4. 3で得たcookieを添えた上でページにアクセスする

3. ログオンページ構成を解析する

最初にするべきことはログオンページ構成を確認することです。 やり方としてページソースを解析しながら進めることでももちろん問題ありませんが、今回はChromeの開発者ツールで通信の中身を見ながら解析をしてみます。

3.1. フォームで利用するユーザ名とパスワードなどのパラメータを確認する

Ctrl+Shift+iでChrome開発者ツールを起動します。 Gitlabのログオンページを開いてから実際にログオンしてみます。

ログオンに成功した際のパラメータを見てみます。

Networkを選択したらNameにあるsign_inを選択します。

下のほうにあるForm Dataを確認してください。 その中に今回のログオンで利用したパラメータが何なのかが表示されています。 具体的には以下のパラメータです。

  1. authenticity_tokens
  2. user[logon]
  3. user[password]
  4. user[rember_me]

また、Generalの部分を見るとStatus Code302でリダイレクトされていることが分かります。

今回はLdap認証化をしていないGitlabで検証していますが、
LDAP認証化したGitlabの際にはパラメータとログオンサイトが異なりますのでご注意ください。
ちなみにLDAP認証化した際には、以下の様になります。 
1. authenticity_tokens
2. username 
3. password 
ログオンURLは`${gitlab_url}/users/auth/ldap/callback`になります。

3.2. csrf対策で送信されているパラメータを確認して取得する

では次にauthenticity_tokensで渡しているパラメータの取得方法についてです。

csrf tokenの値を取得するにはログオンページのソースファイルを見る必要があります。

ソースを開いてcsrfで検索すると以下のような部分があります。この値がcsrf tokenです。 アクセスするタイミングで毎回値は変わります。

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="Dc/t5Bp8jLKDnKc6g3ldvwcVO1Q7+XpbfQB27uelheTdxqLrRk6Qja4XKT0N/9b1vN3fMjvcCJa/WdwEazsf6g==" />

4. crulでのログオン認証ページにアクセスする

では、パラメータが分かったところで以下の処理を実装していきます。 私の環境は以下の通りです。

gitlab_url="[http://xxxxxx](http://192.168.10.31)"
gitlab_user="root"
gitlab_password="pass"
1. ログオンページにGETでアクセスしてcookieを受け取る
2. ログオンページ内のcsrf tokenの値を取得する
3. 1で得たcookieを添えたうえで再度ログオンページアクセスする。
4. さらにユーザ名やパスワード、csrf tokenなどの値を設定してPOSTでアクセスしてログオン認証を実施する。そして再度cookieを受け取る
5. 3で得たcookieを添えた上でページにアクセスする

4.1. ログオンページにGETでアクセスしてcookieを受け取る

まずは初回のログオンページにアクセスします。この時にcookieファイルを保存します。

curl -c cookie01.txt -s -L -X GET "http://192.168.10.31/users/sign_in"

そうするとcookieファイルが新規で作成されることが確認できます。

4.2. ログオンページ内のcsrf tokenの値を取得する

次にcsrf tokenの値を取得します。 先ほどのソースファイルを確認していてcsrf-tokenの行をgrepを使って抽出します。

curl -c cookie01.txt -s -L -X GET "http://192.168.10.31/users/sign_in" | grep csrf-token
<meta name="csrf-token" content="Y0SkL8y9vlwHXTrzclHhm9boPjAHsFqeny/qOoSRQ68u4GK+EitoGT+XPxso+95nlEPYB0pSFUEKrn1h0KglSw==" />

で、さらにsedでいらない部分を消しちゃいます。

curl -c cookie01.txt -s -L -X GET "http://192.168.10.31/users/sign_in" | grep csrf-token | sed -e  's/.*content\=\"//g'  | sed -e 's/\" \/.*//g'
3Tha+3kMshjgVwLFydJ5lMeyZgg/xJqFQL5FSdWvvCzSiJfd8qSDwTTgdOvhSrbVbSUaPOyOyqELNDcyD/DRVw==

4.3. 先ほどのcookieを添えたうえで再度ログオンページアクセス/ログオン認証

先ほどのcookie01.txtを使って、ログオン認証を試してみます。 また、今回の認証に成功した時に保存されるcookieファイルとしてcookie02.txtを保存するようにします。

curl -b cookie01.txt -c cookie02.txt -s -L -F "user[login]=root" -F "user[password]=P@ssw0rd" -F "user[remember_me]=0" -F "authenticity_token=3Tha+3kMshjgVwLFydJ5lMeyZgg/xJqFQL5FSdWvvCzSiJfd8qSDwTTgdOvhSrbVbSUaPOyOyqELNDcyD/DRVw==" "http://192.168.10.31/users/sign_in"

もし、ログオン認証に成功した場合にはcookie02.txtに以下の行(known_sign_inの部分)が追加されているはずです。 cookie01.txtcookie02.txtのサイズも見比べてみて下さい。

#HttpOnly_192.168.10.31 FALSE   /       FALSE   1627794758      known_sign_in   UnV3MnkveGdReTdIOEs5MXRBY3FPM252bm80cUtIQUFtNCsxMWV4R0ZLQ3ZGY1lyVGdjcjlMbU92WDdQSU1nenFIYjBualdzWER6bTAyQkZTQXVHaTRlV0VWWGNuOHlvcXc1SU1McHNTcGJ5amxjaGNnYUJLaTZOUWhaWEtJdXEtLWlZQ1JqY2xCZjRpdE9QY05LdllFemc9PQ%3D%3D--8f29a2a382a02e3b643428e2b0b5e605857453b8

4.4. 認証cookieを添えた上でページにアクセスする

では最後に認証に成功した際のcookieであるcookie02.txtを添えてページにアクセスすることができます。 こんな感じですね。

# curl -b cookie02.txt -I -X GET "http://192.168.10.31/admin/projects"
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 18 Jul 2021 05:17:13 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: max-age=0, private, must-revalidate, no-store
Etag: W/"f2c2fda319a936ed7f3185ee4b25ed0f"
Pragma: no-cache
Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: DENY
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: ggiHdTXmOk
X-Runtime: 0.374683
X-Ua-Compatible: IE=edge
X-Xss-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000
Referrer-Policy: strict-origin-when-cross-origin

ちなみに、cookie02.txtを指定しない場合には以下のように302でサインインページにリダイレクトされる形になります。

[root@gitlab curl_test]# curl  -I -X GET "http://192.168.10.31/admin/projects"
HTTP/1.1 302 Found
Server: nginx
Date: Sun, 18 Jul 2021 05:18:20 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 100
Connection: keep-alive
Cache-Control: no-cache
Location: http://192.168.10.31/users/sign_in
Set-Cookie: experimentation_subject_id=eyJfcmFpbHMiOnsibWVzc2FnZSI6IkltSXpNelprWmpoakxUZGpNRGt0TkRnMVlpMWlNRFZtTFRBME9UUm1ORFV6WVdGbVppST0iLCJleHAiOm51bGwsInB1ciI6ImNvb2tpZS5leHBlcmltZW50YXRpb25fc3ViamVjdF9pZCJ9fQ%3D%3D--b728a632acbe94c7c47d8bc697c02275df6bd599; path=/; expires=Thu, 18 Jul 2041 05:18:20 -0000; HttpOnly
Set-Cookie: _gitlab_session=48e8ca606e7042ff7d40a947b03c5c76; path=/; expires=Sun, 18 Jul 2021 07:18:20 -0000; HttpOnly
X-Request-Id: Fduw65opLu
X-Runtime: 0.018545
Strict-Transport-Security: max-age=31536000
Referrer-Policy: strict-origin-when-cross-origin

5. まとめ

今回はパーツ単位でしたがシェルスクリプトの形にすればGitlabページへのアクセスを自動かする事もできそうですね。

curlでログオン認証するのは場合にもよりますがこのやり方に従ってうまくいけば簡単に実現できるかと思います。

Pythonのオススメ勉強方法

私がオススメするPythonの効果的な学習方法は「Udemy(ユーデミー)」によるビデオ学習です。

「Udemy」は、オンライン学習の提供サイトです。学びたい人は多くある講座の中から受講したいコースを選択することができ、動画で学べるのが特徴です。

多くあるPythonのコースの中でもオススメするPythonのコースは以下となります!!

現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル

このコースでは合計で28.5時間のビデオ講座があって、それらを受講するだけで、Pythonの基礎から応用まで学ぶことができます。

私も購入して受講していますが、内容としては初心者の方から上級者まで対応する幅広い内容になっています。

下手な書籍を何冊か購入するより、この動画コースを最初からじっくりと受けることで総合的なスキルを習得することができるできます。おそらくこれ以上の教材はないと思いますので、絶対おすすめです。

ちなみに、Udemyでは頻繁にセール(1か月に2,3回程度)が開催されているので、セールのタイミングで購入すれば90%OFFになる講座もあるため、セールが開催されてからの購入をオススメします!

今回は以上となります。

コメント

タイトルとURLをコピーしました