1....

21
1. TCP/IP Web, P2P TCP/IP , 1.1 (hierarchical model of protocols) , (each layer offers services to its upper layer) 5 (application layer) [[ : HTTP]] web server/client etc. -----OS ----- system call (transport layer) [[ : TCP, UDP]] (reliable connection) 1-to-1 (network layer) [[ : IP]] IP (datagram) (delivery of datagrams destined to an IP address) (datalink layer) [[ : Ethernet]] (frame) (transmission of frames along a single cable) (physical layer) (ex. ethernet) / (electronic/optical signals) 1.2 TCP/IP (viewed from application programs) OS (identification) IP (32 (IPv4)) (IP address - 32 bits) (identification of hosts) (16 ) (port number - 16 bits) (identification of programs on a host) TCP (establishment of TCP connection) (asymmetric) (receiver side) accept() system call (connection side) IP (using the peer’s IP address and port number) connect() system call , (after the establishment of the connection, the communication is symmetric) (transfered data are just byte streams, without any boundary) accept() , connect() "Connection refused" Routing ? 1.3 (server-client model) : Web, email accept() (the server is accepting connection on a specific port) ex. web -> 80 connect() , , (after connection, the client sends service request and receives the result) TCP/IP , IP , accept() , (Any program can accept connection on a host) , (i.e. anyone can run servers) privileged port 1024 , root ( ) (ports with numbers less than 1024 are only used by administrators)

Upload: others

Post on 19-Oct-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

1. まず一般的なTCP/IPについて Web, P2PアプリケーションはTCP/IPネットワーク上で動作 その原理や特徴, 限界を知っておく必要あり 1.1 プロトコルの階層モデル (hierarchical model of protocols) 各層が提供する相手識別, サービス (each layer offers services to its upper layer) 5層モデル アプリケーション層 (application layer) [[具体例: HTTP]] web server/client etc. -----OSの境界----- system call トランスポート層 (transport layer) [[具体例: TCP, UDP]] 信頼性のあるコネクション (reliable connection) 1-to-1 ネットワーク層 (network layer) [[具体例: IP]] IPアドレスによるパケット(datagram)配送 (delivery of datagrams destined to an IP address) データリンク層 (datalink layer) [[具体例: Ethernet]] 一本のケーブルでのパケット(frame)配送 (transmission of frames along a single cable) 物理層 (physical layer) (ex. ethernet) 電気的信号/光学的信号 (electronic/optical signals) 1.2 アプリケーションからみたTCP/IP (viewed from application programs) つまり、OSが上位に提供する機能 識別 (identification) IPアドレス(32ビット (IPv4)) (IP address - 32 bits) ホストの識別 (identification of hosts) ポート番号(16ビット) (port number - 16 bits) プログラムの識別 (identification of programs on a host) TCP コネクションの設立 (establishment of TCP connection) 非対称 (asymmetric) 受け側 (receiver side) accept() system call 接続要求側 (connection side) 相手のIPアドレスとポート番号を指定して (using the peer’s IP address and port number) connect() system call コネクションが成立してしまえば, 通信は対称 (after the establishment of the connection, the communication is symmetric) データは単なるバイトストリーム (transfered data are just byte streams, without any boundary)    境界なし 相手が accept() してないと, connect() は失敗 "Connection refused" ★Routingの話? 1.3 サーバクライアントモデル (server-client model) 例: Web, email など サーバ側が特定のポート番号で accept() で待つ (the server is accepting connection on a specific port) ex. web -> 80 クライアント側は connect() 接続したら, サービス要求を送信, サービスを受信 (after connection, the client sends service request and receives the result) TCP/IPでは, IPアドレスをもつホスト上で動くプログラムは, accept() で待つことで, すべて接続を受け入れることができる (Any program can accept connection on a host) つまり, だれでもサーバを実行できる (i.e. anyone can run servers) privileged port 1024 未満のポートは, root (管理者)のプログラムだけが使える (ports with numbers less than 1024 are only used by administrators) 一般ユーザが重要なサービスを乗っ取ることを禁止

Page 2: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

(to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える (ports greater than 1024 are available for normal users) ex. http://aaa.bbb.jp:8080/... well known port 特定のサービス向けに予約されたポート (dedicated ports for specific services) /etc/services システムコール socket() - ソケット(通信用データ構造)の作成 bind() - ソケットにポート番号を設定する listen() - 接続待ちの準備 accept() - 接続待ち 返り値はその相手との通信用ソケット 副作用として、相手のアドレスとポートがわかる connet() - 相手に接続をかける read() - データの受信 write() - データの送信 close() - 通信終了 ----------------------------------------------------------- Sample programs in C and Java common.h 1 #include <unistd.h> /* for read, write, close */ 2 #include <string.h> /* for bzero, strlen */ 3 #include <stdlib.h> /* for exit */ 4 #include <stdio.h> 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <netinet/in.h> 8 #include <arpa/inet.h> 9 10 void err(char *s) 11 { 12 fprintf(stderr, "err(%s)\n", s); 13 perror("errno indicates:"); 14 exit(1); 15 } server.c 1 #include "common.h" 2 3 /* 単純なサーバのプログラム 4 クライアントから接続を待ち, 送られてきた10進数文字列を 5 16進数表記文字列に変換して返す */ 6 int main(int argc, char **argv) 7 { 8 int sockfd, newsockfd; 9 socklen_t clilen; /* じつは unsigned int */ 10 struct sockaddr_in cli_addr,serv_addr; 11 char buf[256]; 12 int n, x; 13 14 /* socket システムコール - 返り値はソケットのファイルディスクリプタ */ 15 if ((sockfd = socket(AF_INET,SOCK_STREAM, 0)) < 0) 16 err("server: socket()"); 17 18 /* serv_addr: アドレス/ポート番号を格納するための構造体 */ 19 /* まず 0 でクリア */ 20 bzero((char *) &serv_addr, sizeof(serv_addr)); 21 serv_addr.sin_family = AF_INET; 22 /* 自分のIPアドレスは自動的に設定される */ 23 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 24 /* ポート番号(8888)は自分で設定する */ 25 serv_addr.sin_port = htons(8888);

Page 3: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

26 27 /* bind システムコール - ソケットにポート番号をつける */ 28 if (bind(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0) 29 err("server: bind()"); 30 31 /* listen システムコール - 接続待ちの準備 */ 32 listen(sockfd, 5); 33 34 while(1){ /* サーバは無限ループ */ 35 /* accept システムコール - 接続待ち 36 返り値は通信用のソケット 37 第二引数の cli_addr に, 接続してきた相手のアドレスが入る */ 38 clilen = sizeof(cli_addr); 39 newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen); 40 if (newsockfd < 0) err("server: accept()"); 41 42 /* 通信用ソケットからデータを読み出す */ 43 n = read(newsockfd, buf, sizeof buf); 44 if(n <= 0) err("server: read()"); 45 buf[n] = ’\0’; /* 文字列の終端 */ 46 47 /* データを10進数で解釈して */ 48 sscanf(buf, "%d", &x); 49 /* 16進数として相手に送り返す */ 50 sprintf(buf, "%x", x); 51 n = write(newsockfd, buf, strlen(buf)); 52 if(n <= 0) err("server: write()"); 53 54 /* 通信用ソケットをクローズする */ 55 close(newsockfd); 56 } 57 /* サーバ終了. 接続待ち用ソケットもクローズする */ 58 close(sockfd); 59 exit(0); 60 } client.c 1 #include "common.h" 2 3 /* 単純なクライアントのプログラム 4 第一引数で指定するサーバに接続して第二引数で指定した文字列を送信し, 5 受信した文字列を標準出力に表示する */ 6 int main(int argc, char **argv) 7 { 8 int sockfd; 9 struct sockaddr_in serv_addr; 10 char buf[256]; 11 int i, n; 12 13 /* サーバのアドレスを指定するための構造体の用意 */ 14 bzero((char *) &serv_addr, sizeof(serv_addr)); 15 serv_addr.sin_family = AF_INET; 16 /* サーバのIPアドレスは, 第一引数で 10.0.0.1 のように指定する */ 17 serv_addr.sin_addr.s_addr = inet_addr(argv[1]); 18 /* サーバのポート番号は 8888 で固定 */ 19 serv_addr.sin_port = htons(8888); 20 21 /* socket システムコール - ソケットの生成 */ 22 if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) 23 err("client: socket()"); 24 25 /* connect システムコール - 接続要求 */ 26 if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof serv_addr)<0) 27 err("client: connect()"); 28 29 n = strlen(argv[2]); /* 第二引数 */ 30 /* 文字列を送信する */ 31 i = write(sockfd, argv[2], n);

Page 4: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

32 if(i != n ) err("client: write()"); 33 34 /* サーバからの返事を受信 */ 35 n = read(sockfd, buf, sizeof buf); 36 if(n <= 0) err("client: read()"); 37 /* 標準出力に表示 */ 38 write(1, buf, n); 39 write(1, "\n", 1); /* 改行 */ 40 41 close(sockfd); 42 exit(0); 43 } Server.java 1 import java.io.BufferedReader; 2 import java.io.InputStreamReader; 3 import java.io.PrintStream; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 public class Server { 8 9 public static void main(String[] args) throws Exception { 10 int port = Integer.parseInt(args[0]); 11 ServerSocket ss = new ServerSocket(port); 12 13 while(true){ 14 Socket s = ss.accept(); 15 16 BufferedReader r = 17 new BufferedReader(new InputStreamReader(s.getInputStream())); 18 String msg = r.readLine(); 19 System.out.format("server read: %s\n", msg); 20 21 PrintStream p = new PrintStream(s.getOutputStream()); 22 p.format("Goodby\n"); 23 24 s.close(); 25 if(msg.equals("quit")) break; 26 } 27 ss.close(); 28 } 29 30 } Client.java 1 import java.io.BufferedReader; 2 import java.io.InputStreamReader; 3 import java.io.PrintStream; 4 import java.net.InetAddress; 5 import java.net.Socket; 6 7 8 public class Client { 9 10 public static void main(String[] args) throws Exception { 11 String server = args[0]; 12 int port = Integer.parseInt(args[1]); 13 String to_send = args[2]; 14 Socket s = new Socket(InetAddress.getByName(server), port); 15 16 PrintStream p = new PrintStream(s.getOutputStream()); 17 p.format("%s\n", to_send); 18 19 BufferedReader r = 20 new BufferedReader(new InputStreamReader(s.getInputStream())); 21 String msg = r.readLine(); 22 System.out.format("client read: %s\n", msg);

Page 5: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

23 24 s.close(); 25 } 26 } ----------------------------------------------------------- 1.4 NAT (Network Address Translation) IP(v4)アドレスの枯渇対策 (running out of IP addresses) 組織のネットワークを閉じたものにしてしまう (isolate the internal network of a organization) 内部相互は普通に使える (hosts can communicate within the organization as usual) private address を利用 (using private addresses) IP address の一部, 自由に使ってよい(が, 外部には出せない) 10.xx.xx.xx 192.168.1.xx 外部との通信のために 外部との接続点に NAT Box (broadband router) (connect to the outside using a special router, NAT Box) NAT box の外側には, 正しい(not private) IP address をつける (the outside interface of NAT Box has proper (not private) IP address) 内部→外部の connection (outgoing connection) 発信元IP (source IP address) IP datagram のヘッダに存在 (contained in the IP header) 発信元Port (source port number) TCP datagram のヘッダに存在 (contained in the TCP header) (内部IP, 内部port) → (外部IP, 外部port) と変換 (translate IP address and port number at the NAT Box) TCP接続開始時にこの対応を記憶しておく (and remember the translation in a table) 外部から届いた返信パケットは, この対応表を利用して逆変換 (incoming packets are translated back using the table) 外部→内部の connection (incoming connection) あらかじめ設定してなければ, 破棄 (discarded without any configuration in advance) 設定しておけば, (内部IP, 内部port) に転送 (configure the translation of IP address and port number make the connection to be forwarded to a host in the internal network) 内部にサーバを設置できる (i.e. servers can be located in the internal network) 効果としては (the benefit of NAT) ひとつの(外部)アドレスを使って (only one global IP address) 内部のホストは自由に外部に接続可能 (any number of internal hosts can make outgoing connections) 設定によってはフィルタも可能 (filtering outgoing connection is also possible) 外部からは, NAT Box で static に設定したポートにだけ接続可能 (incomming connection are permitted only if configured explicitly) 一般ユーザは接続を受けることはできなくなる (normal hosts will not receive incoming connection requests) 安全性向上 (increased security) P2Pの観点からは (from the standpoint of P2P) 外部から接続ができない (incoming connections are prohibited) 対称性が崩れる (hosts are not symmetric any more) 2. Web

Page 6: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

2.1 歴史 1989 CERNで提案 素粒子物理実験関連の文書やデータを世界中で交換するため Hypertext ’91 conference Mosaic 1993 - 最初のグラフィカルブラウザ Netscape Navigator, Internet Explorer W3C (World Wide Web Consortium) 1994 2.2 Architectural Overview Web page を表示するシステム 相互のリンク (hyperlink) - hypertext (Vannevar Bush 1945) browser - ページを表示 HTTP (HyperText Transfer Protocol) - TCP上で動作 static page - ファイルに格納されいつも同じ内容 dynamic page - プログラムで生成 / プログラムを含む 2.3 The Client Side URL (Uniform Resource Locator) - ページの名前と場所を示す 例: http://www.uec.ac.jp/index.html protocol (http) ホストのDNS名 (www.uec.ac.jp) パス名 (index.html) リンクをクリックしたときの動作 1. ブラウザはURLを決定 2. DNSでサーバのIPアドレスを問い合わせ 3. DNSでIPアドレスを得る 4. そのIPアドレスの80番ポートへTCPコネクション 5. /index.html を要求するHTTPリクエストを送信 6. サーバはページをHTTPレスポンスとして返す 7. 受け取ったページの中に表示すべきURLが含まれていれば, それらについても同様の手順(2-6)を繰り返す (画像やスクリプト(後述)など) 8. ブラウザは受け取ったページを画面に表示 9. TCPコネクションを閉じる URLは特定のホスト名を含んでいる - そうでない情報は表現できない たとえば特定の文書や特定の本など URN (Uniform Resource Name) 例: 本をISBNで指定 urn:isbn:0451450523 URI (Uniform Resource Identifier) - URL, URN の総称 プレインテキスト以外のページ (画像, 動画, PDF, DOC, ...) MIME Type で区別 - HTTPレスポンス中に存在 (Multipurpose Internet Mail Extension) ファイルの拡張子で区別することもある ブラウザでの表示 Plug-in または Helper application 2.4 The Server Side 動作 (かっこ内は dynamic page のとき) 1. TCPコネクションをacceptする 2. 要求されたパス名を受け取る 3. ディスクからそのファイルを読み出す (あるいはプログラム起動) 4. そのファイルの内容(あるいは処理結果)をクライアントに送信 5. TCPコネクションの解放 2.5 HTTP (HyperText Transfer Protocol) 1991 HTTP 0.9 (と通称) 1996 HTTP 1.0 RFC 1945 1999 HTTP 1.1 RFC 2616 2015 HTTP/2 RFC 7540 TCP上で動作 - 本来はWebのためのアプリケーションプロトコル しかし現代では他のサービスも利用 - 一種のトランスポートプロトコル 自由なポートの接続をフィルタする傾向が強まっていることも原因 例: antivirus software の更新

Page 7: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

HDレコーダ内蔵のWebサーバでコマンド受付 プログラム同士の交信 connection TCP上なので, メッセージ長制限, エラー, 輻輳の心配なし メッセージ HTTP 0.9 (接続) GET <path> <レスポンス: 指定したHTMLファイルの内容> (接続終了) HTTP 1.0 から リクエスト、レスポンスにヘッダがつくようになった ヘッダの終了は空行 一度の接続でリクエスト/レスポンス一対だけだったが HTTP 1.1 から persistent connection 一度の接続で複数のリクエスト/レスポンスを送受信 TCPの接続設定のオーバヘッドを減らせる さらに, レスポンスを待たずに次のリクエストも可能 - pipeline メインページに含まれる画像などを次々に要求できる method GET, HEAD, POST ほかにも各種 status code - レスポンスで返ってくる 1xx Information 2xx Success 3xx Redirection 4xx Client Error 5xx Server Error Message Headers (Wikipedia「Hypertext Transfer Protocol」に一覧あり) リクエストでGETなどの後に続く付加情報 (request header) レスポンスにも付加される (response header) 例: User-Agent (Request) ブラウザに関する情報 If-Modified-Since (Request) ページが更新されているかどうか Content-Type (Response) ページのMIMEタイプ Caching 一度読み出したページをブラウザが保存しておく HTTPヘッダで変更が確認できるので, 変化してなければキャシュを利用 conditional GET 2.5.1 HTTPの観察 Webサーバからの応答を観察 telnet コマンドで要求を送信(ブラウザは使わない) ------------------------------------------------- HTTP 0.9 のリクエスト $ telnet pr.ice.uec.ac.jp 80 Trying 192.168.1.4... Connected to pr.ice.uec.ac.jp. Escape character is ’^]’. (ここでTCP接続完了) GET / (リクエストはこの一行) <HTML> (ここからはサーバのレスポンス; HTMLファイルそのまま) <HEAD> <TITLE>top page</TITLE> <meta http-equiv="Content-Type" content="text/html; charset=euc-jp"> </HEAD> <BODY>

Page 8: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

top page of pr.ice.uec.ac.jp <hr> <a href="~terada/openhouse/"> openhouse on 7/14 </a> <br> <a href="~terada/chofusai/"> openhouse on 11/23 </a> <hr> <ul> <li> <a href="http://sp.ice.uec.ac.jp/"> TERADA Lab.</a> <li> <a href="~terada/"> Minoru TERADA </a> </ul> </body> </html> (ここまででHTMLファイル終了) Connection closed by foreign host. (サーバがTCP接続を切った) ------------------------------------------------- HTTP 1.1 のリクエスト形式 $ telnet pr.ice.uec.ac.jp 80 Trying 192.168.1.4... Connected to pr.ice.uec.ac.jp. Escape character is ’^]’. GET / HTTP/1.1 Host: pr.ice.uec.ac.jp (request header) (この空行でリクエスト完了) HTTP/1.1 200 OK (ここからサーバのレスポンス) Date: Thu, 10 Oct 2013 06:32:49 GMT (response header が並ぶ) Server: Apache Last-Modified: Wed, 10 Jul 2013 14:26:04 GMT ETag: "1083f3-161-ebcb700" Accept-Ranges: bytes Content-Length: 353 Content-Type: text/html (MIMEを使ったデータの種別) (この空行のあとが要求したHTMLファイル) <HTML> <HEAD> <TITLE>top page</TITLE> <meta http-equiv="Content-Type" content="text/html; charset=euc-jp"> </HEAD> <BODY> ...中略... </body> </html> (サーバは次のリクエストを待っている) Connection closed by foreign host. (サーバがタイムアウトして接続を切った) ------------------------------------------------- 2.5.2 Web Proxies Web proxy - 通常は組織の入り口に設置 複数のユーザからのHTTPリクエストを受け, キャシュする ヒット率向上 フィルタリングも可能 NATを使用せずに外部のウェブページを利用可能 ブラウザの設定でproxyを使用 HTTPコネクションはすべて proxy にむかう 2.5.3 Cookies ページの獲得はそれぞれ独立している - 状態をもたない ログインセッションの概念がない あるユーザからの一連のリクエストを他と識別したい IPアドレスでは不十分 NAT だと同一, DHCP では一意でない(割り当てが変化する) RFC 2109 クライアントがページを要求したとき, サーバがCookieを付加してページを返信 ブラウザは受け取ったCookieを保存

Page 9: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

Cookie - 5つのフィールド Domain - サーバのドメイン名 Path - サーバ内のディレクトリパス (サーバ内でのアプリケーションの区別) Content - "name = value" 任意の文字列 Expires - ブラウザでの保存期限 指定なければブラウザ終了時まで - nonpersistent cookie Secure - secure connection のときだけ返送 Cookieを使う ブラウザは以後, 対応するドメイン名のサーバへのHTTPリクエストに 保存しているCookieをすべて返送 サーバはそれを自由に利用できる - たとえば 顧客番号 現在の買い物カートの内容 ユーザがカスタマイズした興味分野(スポーツとか) 訪問回数カウンタ 実演 (http://pr.ice.uec.ac.jp/~terada/learn/php/cookie0.php) 一度目のアクセスと二度目のアクセスで内容が違う ブラウザを再起動すると一度目に戻る cookieのデフォールトの保存期限はブラウザ終了時 ブラウザを再起動すると前のcookieは捨てられる サーバ側でのcookieの利用法 - 上記の例の実装 セッションごとに変数のセットをファイルに保存して利用 ------cookie0.php------ <?php session_start(); ?> <html> <body> <p>012345</p> <?php if (isset($_SESSION[’count’])){ echo "count = ", $_SESSION[’count’]; } else { echo "count undefined."; $_SESSION[’count’] = ""; } $_SESSION[’count’] .= "w"; (文字列の連接) ?> <p>abcdef</p> </body> </html> ------------------------ PHPで session_start() が呼び出されると, クライアントからのリクエストにcookieがあるか確認 ある場合 - そのcookieにひもづいているファイルから変数群を読み出す /var/lib/php/session/<PHPSESSIDの値> 本体を実行 変数群をそのファイルに格納しなおす ない場合 - 新規のcookieを作成して送り返す(PHPSESSID) 本体を実行 変数群をそのファイルに格納する HTTPの観察 前述のtelnetコマンドでの観察では不十分 ローカル側が人間ではなくブラウザだから ブラウザ側からのメッセージも確認するには 一種の proxy をはさむ ブラウザからは proxy として設定 コネクションはすべてそのプログラムへ 到来したコネクションは, 正しい proxy へ中継 その際に通信内容をプリントする

Page 10: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

行頭の0: ブラウザ -> サーバ 行頭の1: サーバ -> ブラウザ ---(一回目)---------------------------------------------- % new connection: 0 Thu Oct 10 16:10:03 JST 2013 /192.168.1.11 49572 proxy-west.uec.ac.jp/1 30.153.8.66 8080 0:GET http://pr.ice.uec.ac.jp/~terada/learn/php/cookie0.php HTTP/1.1 0:Host: pr.ice.uec.ac.jp 0:User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0 0:Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 0:Accept-Language: ja,en-us;q=0.7,en;q=0.3 0:Accept-Encoding: gzip, deflate 0:Connection: keep-alive (ここまで、ブラウザがリクエストに付加するヘッダ) 0: 1:HTTP/1.0 200 OK 1:Date: Thu, 10 Oct 2013 07:10:03 GMT 1:Server: Apache 1:X-Powered-By: PHP/5.1.6 1:Set-Cookie: PHPSESSID=93896v2s04h67mcqe7p1a9ckj5; path=/ 1:Expires: Thu, 19 Nov 1981 08:52:00 GMT 1:Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 1:Pragma: no-cache 1:Content-Length: 78 1:Content-Type: text/html 1:X-Cache: MISS from proxy-west.uec.ac.jp 1:Via: 1.1 proxy-west.uec.ac.jp:8080 (squid/2.7.STABLE7) 1:Connection: keep-alive 1:Proxy-Connection: keep-alive 1: (この空行がresponse headerとページの境界) 1:<html> 1:<body> 1: 1:<p>012345</p> 1: 1:count undefined. (Cookieのあるなしでこの行の反応を変えている) 1:<p>abcdef</p> 1: 1:</body> 1:</html> ---(二回目)---------------------------------------------- 0:GET http://pr.ice.uec.ac.jp/~terada/learn/php/cookie0.php HTTP/1.1 0:Host: pr.ice.uec.ac.jp 0:User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0 0:Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 0:Accept-Language: ja,en-us;q=0.7,en;q=0.3 0:Accept-Encoding: gzip, deflate 0:Cookie: PHPSESSID=93896v2s04h67mcqe7p1a9ckj5 (前に受け取ったCookieを返送) 0:Connection: keep-alive 0:Cache-Control: max-age=0 0: HTTP/1.0 200 OK 1:Date: Thu, 10 Oct 2013 07:10:18 GMT 1:Server: Apache 1:X-Powered-By: PHP/5.1.6 1:Expires: Thu, 19 Nov 1981 08:52:00 GMT 1:Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 1:Pragma: no-cache 1:Content-Length: 71 1:Content-Type: text/html 1:X-Cache: MISS from proxy-west.uec.ac.jp 1:Via: 1.1 proxy-west.uec.ac.jp:8080 (squid/2.7.STABLE7) 1:Connection: keep-alive 1:Proxy-Connection: keep-alive 1: 1:<html> 1:<body> 1:

Page 11: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

1:<p>012345</p> 1: 1:count = w (Cookieのあるなしでこの行の反応を変えている) 1:<p>abcdef</p> 1: 1:</body> 1:</html> ------------------------------------------------- サイトを越えたユーザトラッキング サイトA のページa に広告画像(でなくてもいいが)を貼り付ける http://www.sneaky.com/382674902342.gif サイトB のページb に対しても同様に http://www.sneaky.com/193654919923.gif ページa をアクセスすると, 画像にも要求がいく その時, sneaky.com は Cookie を送信 (たとえば UserID=4627239101) その後, ページb をアクセスしたとき, sneakey.com にはそのCookieが返送される -> ページa, bを閲覧したことがわかる (そのユーザの行動が把握できる) 画像は1ピクセルでも構わない; それをクリックする必要もなし ユーザが気づかないのは問題 自分のブラウザが保存しているCookieを確認しよう ブラウザがCookieを受け取らないように設定することも可能 ただし, サイトの動作に支障がでるケース third-party cookie をブロックする 主ページとは違うサイトからのCookie (上例の sneakey.com) 2.6 HTML (HyperText Markup Language) タグによるマークアップ <b> ... </b> attribute <img src="http://....../.../logo.gif" ALT="LOGO"> hyperlink <a href="http://....."> anchor text </a> ブラウザの view source を利用した観察 進化 HTML 1.0 -> ... -> HTML 5.0 2.6.1 CSS (Cascading Style Sheets) 本来, HTMLは文書の構造を指示するものであるべき (見栄えではなく) しかしデザイン上の要求から詳細な指示が必要になった それを本来の目的どおり分離する仕組み - スタイルシート 別ファイル(たとえば mystyle.css) でスタイルを指定 .htmlファイルからそれを読み込むように指定 <link rel="stylesheet" type="text/css" href="mystyle.css" /> -特定のタグの見栄えを指定 h1 {font-size:200%;} -設定に名前をつける div.command { background-color: #d0ffff; border: none; margin: 10px; padding: 10px; font: x-large monospace; } 使うときは <div>タグ や <span>タグで範囲を指定 <div class="command"> テキスト </div> 2.6.2 Input and Forms 双方向通信 (ユーザからの入力) - HTTP GET/POST メソッドを使用 - HTML Form (ユーザインタフェースのためのボタン, ボックス) HTML 2.0 から

Page 12: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

------- <form ACTION="http://..../action.cgi" method="POST"> <p> Please enter your name: <input type="text" name="name"> </p> <p> Please enter your age: <input type="text" name="age"> </p> <input type="submit"> </form> ------- <input> タグで入力欄やボタンを作成 (type属性に種別) submitボタンが押されるとデータがサーバに返される データはACTIONで指定したURLに送られる その時に使うのが POSTメソッド データを返す通信を観察 formタグでPOSTメソッドを指定した場合, HTTPのボディでフォームの内容を一行で返信 --------------------------------------- POST http://pr.ice.uec.ac.jp/~terada/learn/php/action.cgi HTTP/1.1 Host: pr.ice.uec.ac.jp User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130917 Firefox/17.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 Proxy-Connection: keep-alive Referer: http://pr.ice.uec.ac.jp/~terada/learn/php/test1.html Content-Type: application/x-www-form-urlencoded Content-Length: 18 name=Terada&age=54 --------------------------------------- 下は <form ACTION="http://..../action.cgi" method="GET"> と指定した場合. GETの場合, 要求するURLのあとに ? でフォーム内容を続ける. (したがってボディは空) --------------------------------------- GET http://pr.ice.uec.ac.jp/~terada/learn/php/action.cgi?name=Terada&age=54 HTTP/1.1 Host: pr.ice.uec.ac.jp User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130917 Firefox/17.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 Proxy-Connection: keep-alive Referer: http://pr.ice.uec.ac.jp/~terada/learn/php/test2.html --------------------------------------- 返信されたフォームの情報をサーバ側でどのように受けとるか 2.6.3 Server-Side Dynamic Web Page Generation form -> POST/GET -> server 処理に二つの方法 - CGI, PHP CGI (Common Gateway Interface; RFC 3875) Webサーバが別のプログラムを起動し, フォームの情報を渡す CGIのプログラムは何言語でもOK しかし通常は文字列処理に向いたスクリプト言語 (Perl, Ruby, Python, ...) CGIプログラムの出力は(サーバ経由で)そのままブラウザに返される 普通はHTMLによるWebページの形式にする CGIへのフォームデータの渡り方 POST - CGIプログラムの標準入力として GET - 環境変数 QUERY_STRING の値として 生データを分解してくれるライブラリ/モジュールがある ----------------------------- #! /usr/bin/perl use CGI; $query = new CGI; $person = $query->param("name"); (フォームデータから取り出したパラメータ) $age = $query->param("age") + 1; (フォームデータから取り出したパラメータ)

Page 13: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

print << "EOL"; (ここからブラウザに返すページを出力) content-type: text/html <html><body> Hello $person.<br> Prediction: next year you will be $age. </body></html> EOL exit; ----------------------------- PHP (PHP: Hypertext Preprocessor) HTML中に処理プログラムを埋め込んでおき, WEBサーバがそれを実行 <?php プログラム ?> という形式 ----------------------------- <html> <body> <h1> Reply: </h1> Hello <?php echo $_POST["name"]; ?>. Prediction: next year you will be <?php echo $_POST["age"] + 1; ?> </body> </html> ----------------------------- フォームの値は $_POST[] で得る そのほか JSP (JavaServer Pages) PHPのかわりに Java コードを埋め込む ASP.NET Microsoft 2.6.4 Client-Side Dynamic Web Page Generation PHP, CGIの提供する対話は HTTP の往復が必要 スクリプトの処理はサーバで行うので ユーザの操作にただちに反応するのは困難 HTMLのなかにスクリプト(プログラム)を埋め込み, クライアント(ブラウザ)で実行 <script> タグ (HTML 4.0) dynamic HTML JavaScript 関数 response の定義 form の値の取り出し 結果ページ(document)の作成 submit ボタンにおける onclick=... ----------------------------- <html> <head> <script language="javascript" type="text/javascript"> (プログラムの始まり) function response(test_form) { (関数の定義) var person = test_form.name.value; var years = parseInt(test_form.age.value) + 1; document.open(); (現在表示しているページを書き直す) document.writeln("<html> <body>"); document.writeln("Hello " + person + ".<br>"); document.writeln("Prediction: next year you will be " + years + "."); document.writeln("</body> </html>"); document.close(); } </script> (ここまでプログラム) </head> <body> <form> Please enter your name: <input type="text" name="name"> <p> Please enter your age: <input type="text" name="age"> <p>

Page 14: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

<input type="button" value="submit" onclick="response(this.form)"> </form> </body> </html> ----------------------------- PHP との動作の違い どちらもHTMLにコードを埋め込んでいるが - PHPでは, フォームの結果がサーバに送信され, それを受けてPHPを実行し ブラウザに返信している - JavaScriptでは, サーバとのやりとりなくブラウザがコード実行 VBScript, applets, ActiveX controls いずれもブラウザで実行 例をもう一つ ----------------------------- <html> <head> <script language="javascript" type="text/javascript"> function response() { var x = parseInt(document.getElementById("input_x").value); var y = parseInt(document.getElementById("input_y").value); var result = document.getElementById("result"); result.textContent = x + y; } </script> </head> <body> <input type="text" id="input_x" oninput="response()"> + <input type="text" id="input_y" oninput="response()"> = <span id="result"></span> </body> </html> ----------------------------- 二つ表示されているinputボックスの内容が変化するたびに 合計を計算して表示を更新する DOM (Document Object Model) ブラウザが保持しているページの内容を、 木構造のオブジェクトとしてアクセスできるようにしたモデル html--body--form--input--... 上例では、合計を表示するspanオブジェクト (HTMLソースでは <span></span>タグでくくられている) をプログラムから getElementById で取得し、 その内容を設定することで結果を表示している -「javascript dom reference」で検索 -ブラウザで木構造を表示して吟味することも可能 開発ツールの inspector とか ◯ AJAX - Asynchronous JAvaScript and XML ブラウザ上での高度な対話性と, サーバのデータへのアクセスを結合 Google Gmail, Maps, Docs "not a language; a set of technologies" 1 HTML and CSS 2 DOM 3 XML (eXtensible Markup Language) ブラウザ上のプログラムとサーバとの間の構造をもつデータのやりとり 4 asynchronous way to send and receive XML data 5 JavaScript 2.7 WEB API ここまでの説明では ブラウザ->サーバ: ページ要求, フォーム送信

Page 15: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

サーバ->ブラウザ: HTMLで記述したページ AJAXをはじめとするクライアント側でのプログラム実行では ブラウザ内での描画やコンテンツ生成もあるが サーバからの情報取得の必要 「サーバ上にあるライブラリ関数の呼び出し」モデルで Application Program Interface 関数呼び出しのインタフェースとは 関数名 引数 - 型と個数 返り値 - 型 引数 フォームと同じようにGET/POSTメソッドで送信することが多い 文字列, 数字など 返り値 構造を持ったデータ(オブジェクト)を返す必要もある ネットワークで構造を持ったデータを渡す方法が必要 プログラム言語でいうと 構造体(struct / record / object / hash ...) key-value pair 配列 WEBの世界では XML, JSON などの形式がよく使われる それらへの形式変換をデータの serialize / marshalling / ... という XML - Extensible Markup Language <要素名 属性="値" 属性="値" ...>内容</要素名> JSON - JavaScript Object Notation 配列: [ 値, 値, ... ] オブジェクト: { "キー": 値, "キー": 値, ... } WEBサービスごとにリクエストと応答の形式が決まっている 例: Google Places API (https://developers.google.com/places/documentation/) "Google Places API は、この API 内で施設、地理的位置、有名なスポットとし て定義されているプレイスについての情報を HTTP リクエストを使用して返す サービスです。プレイス リクエストでは、場所を緯度と経度の座標として指定 します。" 検索要求 - あるURLへのGETリクエスト 引数に相当するパラメータはフォームのときと同様に ? と & でエンコード 下の例は 「調布駅周辺100mの登録された地点」を要求 JSON形式での応答を指定している 以下の実行例はシェルからwgetコマンドで直接サーバに要求を送っている (シェルの$xxは変数xxの値に置きかわる) ---------------- output=json key=検索に必要となるキー(登録すると発行してもらえる) location=35.652191,139.543945 radius=100 sensor=false wget -nd "https://maps.googleapis.com/maps/api/place/nearbysearch/$output?location=$locatio n&radius=$radius&key=$key&sensor=$sensor" ---------------- 応答 ---------------- { "html_attributions" : [], 中略 "results" : [ 中略

Page 16: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

{ "geometry" : { "location" : { "lat" : 35.65165, "lng" : 139.544476 } }, "icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/restaurant-71.png", "id" : "bc88b53b4b5c1e3a4f1bc96224afd06f4915f760", "name" : "会津喜多方ラーメン坂内調布店", "opening_hours" : { "open_now" : true }, "photos" : [ 中略 ], "place_id" : "ChIJNdpqSmvwGGARooAPHJsYDf0", "price_level" : 1, "rating" : 3.6, "reference" : 中略, "scope" : "GOOGLE", "types" : [ "restaurant", "food", "establishment" ], "vicinity" : "4 Chome-2-1 Fuda, Chofu" }, 以下略 -------------- XMLでの応答を指定した場合 -------------- 前略 <result> <name>会津喜多方ラーメン坂内調布店</name> <vicinity>4 Chome-2-1 Fuda, Chofu</vicinity> <type>restaurant</type> <type>food</type> <type>establishment</type> <geometry> <location> <lat>35.6516500</lat> <lng>139.5444760</lng> </location> </geometry> <rating>3.6</rating> <icon>http://maps.gstatic.com/mapfiles/place_api/icons/restaurant-71.png</icon> 以下略 -------------- 2.8 プログラムからのWEB APIの利用 - プログラム言語へのラッパー 上記のリクエストと応答をプログラムが処理するためには JSON / XML とプログラム言語固有のデータ構造との相互変換が必要 そのためのライブラリが Wrapper 例: Twitter4j (http://twitter4j.org/ja/index.html) Twitter API を Java言語から利用するための wrapper Twitter が提供するデータ構造に対応したクラスの定義 リクエストを発行するためのメソッドなど ブラウザ上ではない, 独立したアプリケーションからでもWEBサービスの利用が可能 ex. さまざまなTwitterアプリケーション なお、最近はWEBサービスの利用頻度を制限するために, 登録キーを必須にして, それを基準にAPI利用を制限することが多くなってきた - javascript から WEB API を利用してみる

Page 17: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

-- ブラウザから http://pr.ice.uec.ac.jp/~terada/learn/javascript/gethttp/ に 以下の二つのファイルを置く === run-pr.html === <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0.1//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="ja"> <head> <meta http-equiv="Content-Type" Content="text/html;charset=utf8"> <meta http-equiv="Content-Script-Type" content="text/javascript"> <title>gethttp テスト</title> <script src="gethttp-pr.js"></script> </head> <body> <h1>gethttp テスト</h1> <form> <input type="button" value="run" onClick="run()"> </form> <div id="result"></div> </body> </html> === gethttp-pr.js === function run(){ var URL = "http://pr.ice.uec.ac.jp/index.html"; var req = new XMLHttpRequest(); req.open("GET", URL); req.addEventListener("load", function(event){ console.log(event); document.getElementById("result").innerHTML = event.target.responseText; }); req.send(); } ===================== javascriptでは、XMLHttpRequestというクラスのオブジェクトが httpによるコンテンツの取得を行う。 取得が完了すると addEventListener で登録してある関数が 呼び出される(コールバックされる)仕組みになっている ブラウザで runボタンを押すとjavascriptで定義した関数run()が動き、 上記の方法でURLの内容を取得する。 だが、ブラウザによるこの方法は、取り出す側(上記の run-pr.html)と、 取り出される対象(上記のURL)が同じサーバに存在する必要がある。 これはブラウザによる制限で、ユーザが気づかないうちに別のサイトへの WEB API 呼び出しを行わないように保護するためである。 (cross-site request forgeries という) つまり、ブラウザから WEB API 呼び出しを行えるのは 対象サイトにあるページからだけということになる。 -- 独立したjavascriptプログラムから node.js という、ブラウザからは独立して javascript プログラムを 動作させる仕組みがある。 これを利用すると、前述の制限はかからないので、たとえば Google API を 手元から呼び出して結果を利用することができる。

Page 18: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

上述の Google Places API を取得してみる。 === gethttp_node.js === var https=require(’https’); function run(){ var output="json"; var key="検索に必要となるキー"; var location="35.652191,139.543945"; var radius="100"; var sensor="false"; var URL = "https://maps.googleapis.com/maps/api/place/nearbysearch/" + output + "?location=" + location + "&radius=" + radius + "&key=" + key + "&sensor=" + sensor; // APIの引数をGETメソッドのパラメータにエンコード var req = https.get(URL, function(res){ var body = ""; res.on(’data’, function(chunk){ // APIの結果が順次到着 body += chunk; }); res.on(’end’, function(res){ // 取得完了 var result = JSON.parse(body); // 結果のJSONを分解 var results = result[’results’]; // そこから店の配列をとりだし results.forEach(function(r){ console.log(r[’name’]); // 店名をプリント }); }); }); } run(); ===================== (追記) たとえば学内LANからのように、プロキシを経由しないと接続できない&https:の場合、 上記のコードは動かない。プロキシ経由で行うには以下のようにすると 動作するようである。 === gethttp_node.js === var request=require(’request’); function run(){ var output="json"; var key="検索に必要となるキー"; var location="35.652191,139.543945"; var radius="100"; var sensor="false"; var URL = "https://maps.googleapis.com/maps/api/place/nearbysearch/" + output + "?location=" + location + "&radius=" + radius + "&key=" + key + "&sensor=" + sensor; request({ url: URL, proxy: ’http://proxy.uec.ac.jp:8080’ }, function (error, response, body) { if(error){ console.log(error);

Page 19: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

} else { var result = JSON.parse(body); var results = result[’results’]; results.forEach(function(r){ console.log(r[’name’]); }); } }); } run(); ======================= 2.9 HTTP での認証 (authentication) static なページでも使える認証 (HTTPで実装されている) Basic認証 と Digest認証 がある 2.9.1 Basic認証 ディレクトリごとに, アクセスを許可するユーザ名とパスワードを設定 クライアントからアクセスがあったときは, それらを要求 正しければアクセスを認める Apache(ウェブサーバ) での例 ---- .htaccess ---- (対象ディレクトリに置くファイル) AuthType Basic AuthName "Authentication required" AuthUserFile /home/terada/FS/public_html/learn/auth/basic/.htpasswd AuthGroupFile /dev/null Require valid-user ---- .htpasswd ---- (.htaccess で指定した場所に置くファイル) testuser:$apr1$t9dvp/..$1dfGG8ZhVnOEsZtOY15qw0 ユーザ名と, パスワードをハッシュした文字列を格納 (この例では md5 ハッシュ関数を利用) 通信の実行例 (1) client -> server (保護されているディレクトリにあるファイルを要求) 0:GET http://pr.ice.uec.ac.jp/~terada/learn/auth/basic/index.html HTTP/1.1 後略 (2) server -> client (認証できないのでアクセス拒否 401) 1:HTTP/1.1 401 Unauthorized 1:Date: Thu, 22 Oct 2015 06:13:18 GMT 1:Server: Apache 1:WWW-Authenticate: Basic realm="Authentication required" (ここでBasic認証が必要であるとを 示す) 中略 1:Connection: keep-alive 1: 1:<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 1:<html><head> 1:<title>401 Authorization Required</title> 1:</head><body> 1: ... (ここは人間向けの「認証が必要」というメッセージのHTML) 1:</body></html> (3) ブラウザはユーザ名とパスワードを入力するためのポップアップを表示する (4) 人間がそれらを入力すると, client はふたたび server に GET を送る 0:GET http://pr.ice.uec.ac.jp/~terada/learn/auth/basic/index.html HTTP/1.1 0:Host: pr.ice.uec.ac.jp 中略 0:Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3N3b3Jk (ここが人間が入力した認証情報) 0:

Page 20: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

(5) server -> client (認証に成功したのでコンテンツを返信する) 1:HTTP/1.1 200 OK 中略 1:Connection: keep-alive 1: 1:<html> 1:<head> 1:</head> 1:<body> 1:Content (index.html) 1:</body> 1:</html> ステップ(4)で client は認証情報を送っているが, この情報は base64 encoding であって, 容易に復号可能 % echo -n dGVzdHVzZXI6dGVzdHBhc3N3b3Jk | base64 -d testuser:testpassword httpの通信を傍受されると, パスワードが見えてしまう欠点 2.9.2 Digest認証 人間の入力したパスワードを, 平文ではなくハッシュ関数を使って暗号化して送る方式 利用者から見ると, ブラウザの振舞はBasic認証のときと同じ ---- .htdigest ---- (ユーザ名, realm(認証領域) と, MD5でハッシュしたパスワード) testuser:Learn Digest:ed5e2a4618444dba2be6c5496957d2cc 通信の実行例 (1) client -> server (保護されているディレクトリにあるファイルを要求) 0:GET http://pr.ice.uec.ac.jp/~terada/learn/auth/digest/index.html HTTP/1.1 後略 (2) server -> client (認証できないのでアクセス拒否 401) 3:HTTP/1.1 401 Unauthorized 3:Date: Thu, 22 Oct 2015 07:08:05 GMT 3:Server: Apache 3:WWW-Authenticate: Digest realm="Learn Digest", nonce="mR0SKKwiBQA=23b14f0da5e1cdc9d16ae39 6a0bb8da3730039ce", algorithm=MD5, domain="/~terada/learn/auth/digest/", qop="auth" 後略 このとき, サーバは要求する認証情報に関するデータを送ってくる nonce : ランダムな文字列を生成したもの (3) ブラウザはユーザ名とパスワードを入力するためのポップアップを表示する (4) 人間がそれらを入力すると, client はふたたび server に GET を送る 2:GET http://pr.ice.uec.ac.jp/~terada/learn/auth/digest/index.html HTTP/1.1 2:Host: pr.ice.uec.ac.jp 中略 2:Authorization: Digest username="testuser", realm="Learn Digest", nonce="mR0SKKwiBQA=23b14 f0da5e1cdc9d16ae396a0bb8da3730039ce", uri="/~terada/learn/auth/digest/index.html", algorith m=MD5, response="9783d6d1cc4493ddbd5375ef7c6dcccc", qop=auth, nc=00000001, cnonce="9daa8c29 15cbeaeb" 2: client は, 人間が入力したユーザ名 人間が入力したパスワード サーバからの nonce クライアントが作成した cnonce (ランダム文字列) を暗号化して, response としてサーバに送る サーバは 保存されている .htdigest から正しいresponseを求め, response と比較する. 一致したら認証成功. (5) server -> client (認証に成功したのでコンテンツを返信する) 3:HTTP/1.1 200 OK 後略

Page 21: 1. まず一般的なTCP/IPについてpr.cei.uec.ac.jp/~terada/lectures/protocol/2019/note/Net.pdf · (to inhibit normal users from hijacking important services) でも, 1024以上は自由に使える

クライアントによる response の計算を実際に計算してみる (RFC 2617) A1 = testuser:Learn Digest:testpassword (人間の入力内容) A2 = GET:/~terada/learn/auth/digest/index.html MD5(A1) ed5e2a4618444dba2be6c5496957d2cc nonce mR0SKKwiBQA=23b14f0da5e1cdc9d16ae396a0bb8da3730039ce (サーバから入手してある) nc 00000001 cnonce 9daa8c2915cbeaeb (クライアントが生成) qop auth MD5(A2) 69cb0936b11dbc72ef80069036a89fdf response = MD5(MD5(A1) ":" nonce ":" nc ":" cnonce ":" qop ":" MD5(A2)) MD5(ed5e2a4618444dba2be6c5496957d2cc:mR0SKKwiBQA=23b14f0da5e1cdc9d16ae396a0bb8da3730039ce:0 0000001:9daa8c2915cbeaeb:auth:69cb0936b11dbc72ef80069036a89fdf) 9783d6d1cc4493ddbd5375ef7c6dcccc これをサーバは同じ方法で正解をもとに計算して比較する - ネットワーク上を平文のパスワードが流れない - 平文のパスワードは人間の頭の中だけにあればよい cnonceの必要性 attackerが通信(server->client)を横取りして、常に同じnonceを送るようにすると、 attackerは辞書攻撃によって複数のパスワードを少ない労力で破れることになる。 (その唯一nonceで辞書をハッシュしておき、返信のハッシュと比較する) 2.10 OAuth ウェブサービスで, データへのアクセス権限の一部を移譲するための仕組み (認可) 3人の登場人物 - Service Provider データを保持しているサービス (例: Twitter) - User Service Provider の利用者. 自分の認証情報を持っている. - Consumer ユーザの代わりにService Providerの一部の機能を実行するサービス. そのためにユーザのアクセス権限の一部が必要. ウェブサービスの場合 (例: Twitterに連携した各種サービス) 独立したアプリケーションの場合 (例: Twitterクライアント) 認証情報(パスワードなど)をConsumerに渡すのは望ましくない 「全権委任」になる 機能の一部だけを移譲することができない (例: タイムラインの読み出し) 最悪の場合, パスワード変更でアカウント乗っ取り 認可の取消しが難しい 手順 0 Consumer は事前に Service Provider に登録しておく Consumer Key, Consumer Secret 1 User が Consumer にアクセス 2 Consumer は User を Service Provider にリダイレクト 3 User は Service Provider にログインし, Consumer の要求するアクセスを認可 4 認可情報が Consumer へ渡る 5 Consumer は認可情報と引き換えにアクセストークンを入手する Access Token, Access Token Secret 6 Consumer は Service Provider を利用 Consumer Key, Consumer Secret, Access Token, Access Token Secret