ページ 11

SSL通信でfacebookへログインしたい

Posted: 2013年10月04日(金) 23:11
by てるてる
http://fast-uploader.com/file/6936450613891/
pass:ntc2mza
上記アップローダーにソースファイルをアップロードしました。
コンパイラはVC++2010です。通信にはWinSockとOpenSSLを使用しています。

最初のリクエストでログインフォームで発行されるセッションIDのようなものを取得しています。
「lgnrnd」というnameで毎回変動する値がvalueに含まれ、ログインのリクエスト時にPOST送信されています。
なので最初に「lgnrnd」の取得をGETアクセスでしています。
これはちゃんと取得できました。

次のリクエストでログインを試みています。
POSTデータがこれだけでいいのかわからないのですが、とりあえずテスト段階なので、レスポンスを見ながらこの先考えようと思っていたのですが、
この二回目のリクエストを送った後のレスポンスを返ってきません。
なぜでしょうか?

わかる方いらっしゃったらご教授ください。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月04日(金) 23:22
by みけCAT
OpenSSLはよくわからないのですが、1回目のリクエストの後サーバーとの接続が切れているのではないでしょうか?
リクエストごとにサーバーに繋ぎ直してみたらどうなりますか?
もしくは、まずGET(同じリクエスト)を同じように2回行い、2回ともレスポンスが帰ってくるか試してみてください。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 08:21
by てるてる
みけCAT さんが書きました:OpenSSLはよくわからないのですが、1回目のリクエストの後サーバーとの接続が切れているのではないでしょうか?
リクエストごとにサーバーに繋ぎ直してみたらどうなりますか?
もしくは、まずGET(同じリクエスト)を同じように2回行い、2回ともレスポンスが帰ってくるか試してみてください。
ret = SSL_write(ssl,request,strlen(request));
if(ret < 1)
{
ERR_print_errors_fp(stderr);
exit(1);
}

一応SIGPIPEが発生してないかのチェックは入れています。
ここでの終了はないので接続が切れてるということはないと思います。

また、GETを同じように2回行うこともやってきています。
2回目のレスポンスが返ってきません。

仮に、facebookへログインできるできないは置いといて、
一回目のGETリクエストをコメントアウトし、
二回目のPOSTリクエストだけにしてみました。
そうするとちゃんとレスポンスは返ってきましたので、
リクエスト方法に間違えはないのかな?と思ってるのですが。。。


まとめると
・1回目のGETリクエストはレスポンスが返ってくるが、2回目のPOSTリクエストではレスポンスが返ってこない。
・2回目のリクエストをPOSTではなくGETにしてみたがレスポンスが返ってこない。
・1回目のリクエストをコメントアウトし、2回目だけリクエストを送るようにするとレスポンスは返ってくる。
・1回目のリクエストが終わり、2回目のリクエスト送信時にSIGPIPEは発生していないので、接続が切れているということはない。


いかがでしょうか?
なぜこのようなことが起こるのか不思議でなりません。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 09:58
by みけCAT
1回目に送られてくるヘッダを見たときに、Connection: closeという行はありますか?
もしこの行があれば、この通信は今のリクエストへのレスポンスを送信し終わったら切断する、ということを示します。
逆に、Connection: Keep-Aliveという行があれば、接続は今のリクエストへのレスポンスを送信し終わっても切断されないことを示します。
オフトピック
Windowsでシグナルは発生するのだろうか?
(そもそも質問者が言うSIGPIPEとやらがLinuxのシグナルを示すかどうかがわからないが)

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 10:37
by てるてる
みけCAT さんが書きました:1回目に送られてくるヘッダを見たときに、Connection: closeという行はありますか?
もしこの行があれば、この通信は今のリクエストへのレスポンスを送信し終わったら切断する、ということを示します。
逆に、Connection: Keep-Aliveという行があれば、接続は今のリクエストへのレスポンスを送信し終わっても切断されないことを示します。
オフトピック
Windowsでシグナルは発生するのだろうか?
(そもそも質問者が言うSIGPIPEとやらがLinuxのシグナルを示すかどうかがわからないが)
HTTP/1.0 200 OK
Cache-Control: private, no-cache, no-store, must-revalidate
Expires: Sat, 01 Jan 2000 00:00:00 GMT
P3P: CP="Facebook does not have a P3P policy. Learn why here: http://fb.me/p3p"
Pragma: no-cache
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0
Set-Cookie: datr=D21PUnfY5_qkfCAtCMPlnGOs; expires=Mon, 05-Oct-2015 01:36:15 GMT
; path=/; domain=.facebook.com; httponly
Set-Cookie: reg_ext_ref=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/;
domain=.facebook.com
Set-Cookie: reg_fb_gate=https%3A%2F%2Fwww.facebook.com%2F; path=/; domain=.faceb
ook.com
Set-Cookie: reg_fb_ref=https%3A%2F%2Fwww.facebook.com%2F; path=/; domain=.facebo
ok.com
Content-Type: text/html; charset=utf-8
X-FB-Debug: TUFjusd1yiFmbpemBJiq8H52ubhGmYFKX2PoIxRuKos=
Date: Sat, 05 Oct 2013 01:36:15 GMT
Connection: keep-alive
Content-Length: 43544

これがレスポンスです。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 10:44
by てるてる
firefoxのアドオンであるFirebugでどのようなリクエストを出しているかを調べてみました。

GET / HTTP/1.1
Host: www.facebook.com
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:24.0) Gecko/20100101 Firefox/24.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
Connection: keep-alive

このようになっています。

私の場合
sprintf(request, "GET / HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:24.0) Gecko/20100101 Firefox/24.0\r\n"
"Connection: keep-alive\r\n"
"Keep-Alive: 300\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\n",host);
このようにしています。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 11:05
by みけCAT
2回目のリクエストは送信されていますか?
自分の環境でテストしたところ、1回目のリクエストのSSL_readでブロッキングが発生していました。
きちんとContent-LengthやContent-encoding: chunkedの処理をした方がいいかもしれません。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 11:12
by みけCAT
このプログラムだと、たまたまname="lgnrnd"という文字列が受信ブロックの境界で分割されると検出できないですし、
name="lgnrnd"とその次の/の間に境界がたまたま来てしまうと、おそらく無限(かもしれない)ループになり、アクセス違反で死にます。
現状でうまくいったとしても、「たまたま」境界がいい感じの位置になったからです。
このくらいのサイズのレスポンスでしたら、一度レスポンスのテキスト全体をメモリに乗せ、そこで文字列探索をすることをおすすめします。
もしくはきちんと境界の分割を考え、前の数ブロックを保持する方法もありますが、複雑になります。

これを踏まえた上でとりあえず2回目のリクエストを送る方法ですが、
1回目のリクエストの受信中、

コード:

buf[read_size] = '\0';
の次の行に

コード:

if(strstr(buf,"\r\n0\r\n")!=NULL)break;
という行を入れてください。
サーバーがContent-encoding: chunkedでレスポンスを返し、かつこの部分が受信ブロック境界をまたがなかった場合、
レスポンスの終端を判定でき、ループを抜けられます。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 11:15
by みけCAT
ところで、WinInetを使ってはいけない理由はありますか?
(Linuxなどへの対応、縛りプレイ、OpenSSLやHTTPの勉強など)

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 12:15
by てるてる
みけCAT さんが書きました:このプログラムだと、たまたまname="lgnrnd"という文字列が受信ブロックの境界で分割されると検出できないですし、
name="lgnrnd"とその次の/の間に境界がたまたま来てしまうと、おそらく無限(かもしれない)ループになり、アクセス違反で死にます。
現状でうまくいったとしても、「たまたま」境界がいい感じの位置になったからです。
このくらいのサイズのレスポンスでしたら、一度レスポンスのテキスト全体をメモリに乗せ、そこで文字列探索をすることをおすすめします。
もしくはきちんと境界の分割を考え、前の数ブロックを保持する方法もありますが、複雑になります。

これを踏まえた上でとりあえず2回目のリクエストを送る方法ですが、
1回目のリクエストの受信中、

コード:

buf[read_size] = '\0';
の次の行に

コード:

if(strstr(buf,"\r\n0\r\n")!=NULL)break;
という行を入れてください。
サーバーがContent-encoding: chunkedでレスポンスを返し、かつこの部分が受信ブロック境界をまたがなかった場合、
レスポンスの終端を判定でき、ループを抜けられます。
ありがとうございます。
無事に2回目のリクエスト送信ができました。

>このくらいのサイズのレスポンスでしたら、一度レスポンスのテキスト全体をメモリに乗せ、そこで文字列探索をすることをおすすめします。
どういうことでしょうか?
char buf[BUF_LEN];

BUF_LENをテキスト文字数にするということですか?

文字列探索の方法としては本来は正規表現を使えればいいのですが、ライブラリがよくわからず適当に処理させてしまっていました。
今後も下記のようなクッキーの取得などで文字列探索を頻繁に使うことになると思います。
Set-Cookie: datr=値; expires=Mon, 05-Oct-2015 03:13:23 GMT
; path=/; domain=.facebook.com; httponly
何かいい方法をご存じでしたら教えていただきたいのですが・・・

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 12:19
by てるてる
みけCAT さんが書きました:ところで、WinInetを使ってはいけない理由はありますか?
(Linuxなどへの対応、縛りプレイ、OpenSSLやHTTPの勉強など)
HTTPの勉強ということもありますが、WinInetというのを知りませんでした。
「SSL通信するのだからOpenSSLを使わなければ」と勝手に思い込んでしまいライブラリをインストールしました。
他のパソコン(Windows)でも使用したいのですが、OpenSSLライブラリをインストールしている人は少ないと思うので
WinInetを使った方がいいのでしょうか?
OpenSSLだと使用者にライブラリのインストールを強制させてしまうことになりますか?

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月05日(土) 13:10
by みけCAT
てるてる さんが書きました:>このくらいのサイズのレスポンスでしたら、一度レスポンスのテキスト全体をメモリに乗せ、そこで文字列探索をする ことをおすすめします。 どういうことでしょうか? char buf[BUF_LEN]; の BUF_LENをテキスト文字数にするということですか?

文字列探索の方法としては本来は正規表現を使えればいいのですが、ライブラリがよくわからず適当に処理させてし まっていました。 今後も下記のようなクッキーの取得などで文字列探索を頻繁に使うことになると思います。 Set-Cookie: datr=値; expires=Mon, 05-Oct-2015 03:13:23 GMT ; path=/; domain=.facebook.com; httponly 何かいい方法をご存じでしたら教えていただきたいのですが・・・
C言語縛りですか?
レスポンスの文字数は予測が難しいと思うので、動的確保をするべきです。
C言語ならreallocか、Windows APIのヒープならHeapReallocでバッファを足していきます。
C++を使ってよければ、std::stringを使うのが簡単です。

正規表現は、C++ならboostというライブラリが使えるかもしれませんが、よくわかりません。
Windowdならbregexp.dllというライブラリもあります。
てるてる さんが書きました:OpenSSLだと使用者にライブラリのインストールを強制させてしまうことになりますか?
OpenSSLはスタテイックリンクライブラリもあるので、その可能性は低いはずです。
むしろWinInetを使う方が、Windowsの使用を強制してしまうことになります。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月06日(日) 10:42
by てるてる
みけCAT さんが書きました:
てるてる さんが書きました:>このくらいのサイズのレスポンスでしたら、一度レスポンスのテキスト全体をメモリに乗せ、そこで文字列探索をする ことをおすすめします。 どういうことでしょうか? char buf[BUF_LEN]; の BUF_LENをテキスト文字数にするということですか?

文字列探索の方法としては本来は正規表現を使えればいいのですが、ライブラリがよくわからず適当に処理させてし まっていました。 今後も下記のようなクッキーの取得などで文字列探索を頻繁に使うことになると思います。 Set-Cookie: datr=値; expires=Mon, 05-Oct-2015 03:13:23 GMT ; path=/; domain=.facebook.com; httponly 何かいい方法をご存じでしたら教えていただきたいのですが・・・
C言語縛りですか?
レスポンスの文字数は予測が難しいと思うので、動的確保をするべきです。
C言語ならreallocか、Windows APIのヒープならHeapReallocでバッファを足していきます。
C++を使ってよければ、std::stringを使うのが簡単です。

正規表現は、C++ならboostというライブラリが使えるかもしれませんが、よくわかりません。
Windowdならbregexp.dllというライブラリもあります。
てるてる さんが書きました:OpenSSLだと使用者にライブラリのインストールを強制させてしまうことになりますか?
OpenSSLはスタテイックリンクライブラリもあるので、その可能性は低いはずです。
むしろWinInetを使う方が、Windowsの使用を強制してしまうことになります。
C++がよくわかりません。
C言語での開発がわかりやすいのでHeapReallocでやってみます。

bregexp.dllというのを調べてみます。
正規表現が使えたら今後もかなり楽になると思います。


それともう一つ問題があるのですが、
HTTPリクエストだけでonclickやonkeydownで発生させることはできないのでしょうか?
どうやらonkeydownでセッション用のinputタグを投入させているようです。
POSTデータにこのセッションを入れないとダメらしいのですが、何か方法はありますか?

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月06日(日) 10:48
by みけCAT
動的確保には、reallocなどでバッファを再確保する方法の他に、取得したデータをリンクリストで持ち、
全部のデータを取得してサイズがわかったあとに必要なバッファを確保してコピーする、という方法もあります。
reallocなどによる再確保とどっちの方が効率がいいかは知りません。
てるてる さんが書きました:それともう一つ問題があるのですが、
HTTPリクエストだけでonclickやonkeydownで発生させることはできないのでしょうか?
どうやらonkeydownでセッション用のinputタグを投入させているようです。
POSTデータにこのセッションを入れないとダメらしいのですが、何か方法はありますか?
HTTPで相手(Facebook)のサーバーと通信するだけでは無理です。
onclickやonkeydownはJavascriptの処理です。
次のような対応策が考えられます。
・必要なパラメータを取得し、自分でJavascriptに相当する処理を書いてデータを作る
・V8エンジンなどで直接Javascriptを処理する(?)

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月06日(日) 12:25
by h2so5
FacebookのWebブラウザからのログインをエミュレートする理由がよく分かりません。
公式のFacebookAPIを利用するほうが良いと思うのですが。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月06日(日) 12:55
by てるてる
h2so5 さんが書きました:FacebookのWebブラウザからのログインをエミュレートする理由がよく分かりません。
公式のFacebookAPIを利用するほうが良いと思うのですが。
Web用やiOS、Androidなら調べれば出てきたのですが、
C言語を使ってWindows上で動作させる方法など調べてもわからなかったので、自分で作ろうと思いました。
最終的には自分が所属しているグループへの投稿なのですが。。。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月06日(日) 13:29
by h2so5
公式APIからのグループへの投稿はこのドキュメントが参考になると思います。
HTTPSリクエストで投稿できるようです。

https://developers.facebook.com/docs/re ... ublishing/
https://developers.facebook.com/docs/re ... api/group/

ブラウザの挙動をエミュレートするのは面倒が多いだけでメリットが0なので止めたほうがいいです。
仕様変更に対応できない上に、APIを迂回する悪質なBOTと間違われる可能性もあります。

Re: SSL通信でfacebookへログインしたい

Posted: 2013年10月06日(日) 14:29
by てるてる
h2so5 さんが書きました:公式APIからのグループへの投稿はこのドキュメントが参考になると思います。
HTTPSリクエストで投稿できるようです。

https://developers.facebook.com/docs/re ... ublishing/
https://developers.facebook.com/docs/re ... api/group/

ブラウザの挙動をエミュレートするのは面倒が多いだけでメリットが0なので止めたほうがいいです。
仕様変更に対応できない上に、APIを迂回する悪質なBOTと間違われる可能性もあります。
C言語からAPIを使う方法があれば使ってもいいのですが、調べても出てこなかったもので・・・