筑波大学 システム情報系 情報工学域 新城 靖 <yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
https://www.coins.tsukuba.ac.jp/~syspro/2024/2024-07-31/index.html
あるいは、次のページから手繰っていくこともできます。
https://www.coins.tsukuba.ac.jp/~syspro/2024/
http://www.coins.tsukuba.ac.jp/~yas/
$ id yas
uid=1013(yas) gid=5510(prof) groups=5510(prof),6023(coins-2024),5020(c-admin),
6019(coins-2019),5065(c-spec),5150(tebiki),6000(c-comp),5180(c-gakusei)
$ getent passwd yas
yas:*:1013:5510:Yasushi SHINJO:/home/prof/yas:/bin/bash
$ id apache
uid=48(apache) gid=48(apache) groups=48(apache)
$ getent passwd apache
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
$ ps aux | egrep apache | head -3
apache 2095 0.0 0.2 2377784 43344 ? Sl 7月05 2:28 /usr/sbin/httpd -DFOREGROUND
apache 2096 0.0 0.2 2377784 47796 ? Sl 7月05 2:32 /usr/sbin/httpd -DFOREGROUND
apache 2097 0.0 0.3 2443320 49896 ? Sl 7月05 2:29 /usr/sbin/httpd -DFOREGROUND
$
HTML ファイルや CGI のファイルは、この UID のプロセスからアクセスできる
状態でなければならない。アクセスできない時には、Web サーバは、HTTP のヘッ
ダの status line では 403 Forbidden
、本文では HTML で次のような
ものを返す。
Forbidden You don't have permission to access /~ユーザ名/・・・ on this server.
この状態を修復するには、Web サーバが HTML や CGI のファイルがアクセスよ
うにする。すなわち、自分でもグループでもなく、その他のユーザが HTML ファ
イルを read できるか、CGI のプログラムを exec できるかを確認する。
$ ls -l cgi-hello.cgi
-rwxr-xr-x 1 yas prof 8488 6月 14 12:04 cgi-hello.cgi
$
システムコールを使ったファイルのコピー(filecopy-syscall.c)
で出てきた次の部分に注目。
18 fpd = open("dst", O_WRONLY | O_CREAT | O_TRUNC, 0644);こうして作成されたファイルのモードは、最大
644
(rw-r--r--) になる。
umask が 0022 なら、これも引かれる。
umask が 0022 なら、次のようにしても 644 のファイルが作成される。
シェルの標準出力のリダイレクションでは、0666 が使われている。
fpd = open("dst", O_WRONLY | O_CREAT | O_TRUNC, 0666);
アクセスできるかどうかは、末端のファイルだけでなく、ルートディレクから このファイルに至るまでのディレクトリのモード(xビット)も関係する。
/home/prof/yas/public_html/syspro-cgi-examples/cgi-hello.cgi
ホーム・ディレクトリのモードが次のように 700
(rwx------
)
になっていると、Web ページを公開することはできない。Web サーバのプロセ
スは、このホームディレクトリ以下のファイルを一切アクセスできない。
$ ls -ld ~
drwx------ 36 s2154321 ugrad 4096 2月 12 23:23 /home/ugrad/21/s2154321
$
少なくとも、次のように 701
(rwx-----x
)になっていなければ
ならない。
$ ls -ld ~
drwx-----x 36 s2154321 ugrad 4096 2月 12 23:23 /home/ugrad/21/s2154321
$
ホームディレクトリのモードを変更すると、Web ページは公開できるようにな
るが、その副作用として、他人がファイル名を知っていれば、レポートのファ
イル等をアクセス可能になることがある。他人にアクセスさせたくなければ、
ホームディレクトリではなく、それ以下の個々のファイルやディレクトリのモー
ドを変更する必要がある。変更する前に、この点をきちんと理解すること。
ディレクトリのxの働き 参照。
JavaScript は、文法が少し Java 言語に似ているが、Java とはまったく別の 言語である。 JavaScript の記述は、「実行可能なインライン・テキスト」と言える。
JavaScrip のプログラムの例:
<SCRIPT LANGUAGE="JavaScript"> <!-- for( i=0 ; i<10; i++ ) document.writeln("<P>hello,world</P>"); //--> </SCRIPT>これは、
<P>hello,world</P>
を 10 回書いた
のと同じ効果がある。<!--
と
//->
は、JavaScriptを知らないブラウザにはコメント
として扱われる。関数定義などは、ヘッダ部分
<HEAD></HEAD>
に書くという方法もよく使われる。
for
、while
、
if
, else
, continue
,
break
, switch case
がある。
try
,
catch
,
throw
による例外を扱う機能がある。
function
で、関数定義ができる。
var
で宣言すれば、ローカル変数になる。
配列は、new Array(長さ)
で確保する。
class
というキーワードは、もともとはない(EcmaScrypt 6 2015で導入)。
function
に new
を付けて呼べば、オブジェ
クトになる。オブジェクトのメソッドでは、this
を使っ
て要素を参照できる。
自分で持っていないフィールドは、プロトタイプを探しにいく。
JavaScript の記述は、CGI と似ているところもあるが、JavaScript でないと
できないものに、ブラウザの制御がある。たとえば、次の例では、ブラウザの
(戻る
)ボタンと同じ動きをさせることができる。
<A HREF="javascript:history.back();">[戻る]</A>
次の例は、<FORM></FORM>
からパラメタを受け取るも
のである。
<SCRIPT LANGUAGE="JavaScript"> <!-- function go(s,h,p) { location.href = s.value + "://" + h.value + p.value ; } //--> </SCRIPT> <FORM NAME="form1"> Scheme: <INPUT NAME="scheme" TYPE="text" VALUE="http"><BR> Host: <INPUT NAME="host" TYPE="text"><BR> Path: <INPUT NAME="path" TYPE="text" VALUE="/"><BR> <INPUT TYPE="button" VALUE="go" onClick="go(form1.scheme,form1.host,form1.path)"> </FORM>
onClick
属性の値は、クリックした時に評
価される式であり、関数 go()
が呼び出されている。引
数は、<FORM>
の値である。関数
go()
の中では、
.value
フィールドから値が読み出されている。
location.href
に代入することで
そのページを表示させることができる。
この例では、<INPUT type="text">
と
<INPUT type="button">
が使われている。その他に、
<FORM>
では、<INPUT
TYPE="radio">
、<INPUT TYPE="checkbox">
、
<SELECT>
が使える。イベントとしては、
onClick
が主に使われる。その他に、
onFocus
が使われることもある。
JavaScript では、document.open()
で新しく HTML の
ドキュメントを生成して、それをブラウザに表示させることもできる。
Webブラウザでは、信頼しているサイトから送られてくるJavaScriptのプログ ラムだけを実行するようにし、攻撃サイトから送られてくるJavaScriptのプロ グラムを実行しないようにしたい。
Web ブラウザは、 同一オリジンポリシー(Same Origin Policy) を実装している。Web サイト(origin) ごとに cookie や localStorage が隔離 される。ある Web サイトから届いた JavaScript のプログラムは、他のWeb サ イトのデータをアクセスする時に規制を受ける。
図? JavaScripの送信元サイトの区別
脆弱性があるサイトでは、Web ブラウザを経由して 攻撃サイトから送られてき た JavaScript のプログラムを中継してしまう。 悪意のある JavaScript のプログラムが、 攻撃サイト−>Webブラウザ−脆弱性のあるサイト−>Webブラウザと 中継され、実行される。 悪意のある JavaScript のプログラムが、脆弱性のある Web サイトに関連した データを自由にアクセスできる。
図? JavaScripの送信元サイトの区別
クライアントから送られてる文字列の中に
<SCRIPT>のようなタグが含まれていた場合、それをそのままクラ
イアントに送り返すと問題がある。
(さらに、
%hh
にも気をつける必要がある。)
クライアントから送られてきた文字列は、必ず検査し、安全な状態にして (sanitize)から使う。「<>&"」のようなタグが含まれている場合 には注意する。このような文字列を受け取った場合、不用意に送り返してはい けない。送り返す時には、html_escape() のよう な方法で必ずエスケープする。
むやみにエスケープすれば安全になるというものでもない。 エスケープするのは、クライアントから送られてきたデータに由来するものだ けで良い。サーバ側で生成したもの、たとえば、10+20 を計算して得られた整 数 30 を"%d" で表示したようなものは、エスケープする必要はない。
abc<>&012
abc<>&012
184: char * 185: html_escape( char *str ) 186: { 187: int len ; 188: char c, *tmp, *p, *res ; 189: 190: len = strlen( str ); 191: tmp = malloc( len * 6 + 1 ); 192: if( tmp == 0 ) 193: return( 0 ); 194: p = tmp ; 195: while( (c = *str++) ) 196: { 197: switch( c ) 198: { 199: case '&': memcpy(p,"&", 5); p += 5 ; break; 200: case '<': memcpy(p,"<", 4); p += 4 ; break; 201: case '>': memcpy(p,">", 4); p += 4 ; break; 202: case '"': memcpy(p,""",6); p += 6 ; break; 203: default: *p = c ; p++ ; break; 204: } 205: } 206: *p = 0 ; 207: res = strdup( tmp ); 208: free( tmp ); 209: return( res ); 210: } 211:html_escape() は、次の文字を置換えている。それ以外の文字はそのままコピー している。
文字 変換後の文字列 ---------------------- & & < < > > " "もし、<SCRIPT> のような文字列がクライアントから送られてきた としても、html_escape() で置換ると、クライアントには 「<SCRIPT>」と返すだけで、スクリプトは実行されない。
len * 6 は、最大で元の文字列の6倍の長さになることに備えている。 メモリの断片化が起きやすいので、良いコードとは言えない。
普通のプログラミング言語は、アプリケーション・プログラム本体を記述する 時に使われる。 これに対して、 スクリプト言語 は、アプリケーション本体で はなく、アプリケーションの細かな動作を変更したり、アプリケーション本体 を変更することなく機能を追加したりするために使われる言語である。
普通のプログラミング言語は、アプリケーション・プログラマにより使われ、 コンパイラで機械語に変換されるので、実行時には機械語しか残っていない。 これに対して、スクリプト言語は、アプリケーションのユーザや、システム管 理者などによって使われ、プログラムは、アプリケーションに組み込まれた インタプリタで解釈実行される。
スクリプト言語を使うと、単に変数を設定することに比べて、 高度な機能拡張が機能になる。
シェル・スクリプト を使うと、OS本体(C言語で記述)の機能を拡張できる。
cat コマンドは、テキストファイルを画面に表示する時に使うコマンドである (補講)。 引数で与えられた名前のファイルを open し、read し、それを標準出力に write する。 -n オプションをつけると、行番号を表示する。 ファイル名の引数が与えられないと、標準入力から read したものを標準出力に write する。
$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/usr/bin/sh
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/bin/ksh93
/usr/bin/ksh93
/bin/rksh93
/usr/bin/rksh93
/bin/zsh
/usr/bin/zsh
/bin/tcsh
/usr/bin/tcsh
/usr/bin/fish
$ cat -n /etc/shells
1 # /etc/shells: valid login shells
2 /bin/sh
3 /bin/bash
4 /usr/bin/bash
5 /bin/rbash
6 /usr/bin/rbash
7 /usr/bin/sh
8 /bin/dash
9 /usr/bin/dash
10 /usr/bin/tmux
11 /bin/ksh93
12 /usr/bin/ksh93
13 /bin/rksh93
14 /usr/bin/rksh93
15 /bin/zsh
16 /usr/bin/zsh
17 /bin/tcsh
18 /usr/bin/tcsh
19 /usr/bin/fish
$ cat
abc
abc
012
012
^D
$ cat -n
abc
1 abc
012
2 012
^D
$
cat コマンドは「ファイル(プログラム)を表示する」インタプリタである。 まず、「catインタプリタ」用の2行のプログラムを作成する。
$ cat > run-cat
#!/bin/cat
hello
^D
$ cat run-cat
#!/bin/cat
hello
$ ls -l run-cat
-rw-r--r-- 1 yas prof 17 7月 7 17:33 run-cat
$ ./run-cat
bash: ./run-cat: 許可がありません
$ chmod +x run-cat
$ ls -l run-cat
-rwxr-xr-x 1 yas prof 17 7月 7 17:33 run-cat
$
「catインタプリタ」用のプログラムを実行する。
$ ./run-cat
#!/bin/cat
hello
$
これは次のように実行したものと同じになる。
$ /bin/cat ./run-cat
#!/bin/cat
hello
$
cat コマンドに -n オプション(行番号をつける)を与えてみる。
$ emacs run-cat
$ cat run-cat
#!/bin/cat -n
hello
$
実行してみる。
$ ./run-cat
1 #!/bin/cat -n
2 hello
$
これは次のように実行したものと同じになる。
$ /bin/cat -n ./run-cat
1 #!/bin/cat -n
2 hello
$
/dir/interpreter
という名前のインタプリタを実行したい。
filename
という名前のファイルに保存する。
filename
の内容:
#!/dir/interpreter opt-1 opt-2 opt-3 <以下、プログラム>このファイルに実行可能属性を付ける(
chmod +x
)と、
ファイル名を入力して実行することができる。
$ chmod +x ./filename
$ ./filename arg-a arg-b arg-c
<実行結果>
これは、次のようにインタプリタを起動したものと同じ結果になる。
Linux, FreeBSD の場合:
$ /dir/interpreter 'opt-1 opt-2 opt-3' ./filename arg-a arg-b arg-c
macOS の場合:
$ /dir/interpreter opt-1 opt-2 opt-3 ./filename arg-a arg-b arg-c
Solaris の場合:
$ /dir/interpreter opt-1 ./filename arg-a arg-b arg-c
./filename
ファイルに書いた引数は、シェルから実行する時場合には、
インタプリタのプロセスへの引数として渡される。
#!
」行は、Unix のカーネルが解釈する
(
補講/シェルとカーネルの関係
)
。
シェルが、ファイルの先頭を読み、指定されたインタプリタを起動するのでは
ない。「#!
」行では、シェル変数、環境変数、エイリアスはつ
かえない。
スクリプト言語のプログラムでは
「#
」から始まる行がコメントであると都合がよい。
awk
や sed
のように、プログラムが含まれたファイルを指定
する時に -f
(program file) オプションが必要なものは、次の
ように、この行に -f
を付ける。
#!/usr/bin/awk -f { print }
オペレーティング・システムのカーネルは、現在の所、C言語で記述されていることが多い。 シェルは、オペレーティング・システムの機能を拡張する。
シェル・スクリプトの先頭の
#!/bin/sh
や
#!/bin/csh
は、
そのインタプリタを起動するという意味である。
情報科学類の学生は、シェルスクリプトくらい作れるようになりたい。
cgi-hello-sh.txt
]
$ cat cgi-hello-sh.cgi
#!/bin/sh
cat <<EOF
Content-Type: text/html
<HTML><HEAD></HEAD><BODY>
hello.
</BODY></HTML>
EOF
$ ./cgi-hello-sh.cgi
Content-Type: text/html
<HTML><HEAD></HEAD><BODY>
hello.
</BODY></HTML>
$
http://www.coins.tsukuba.ac.jp/~syspro/2024/2024-07-31/cgi-hello-sh.cgi
1: #!/usr/local3/coins/linux/bin/ruby 2: # -*- coding: utf-8 -*- 3: # cgi-printarg-ruby.cgi -- CGI プログラムに対する引数を表示するプログラム 4: # ~yas/syspro/www/cgi-printarg-ruby.cgi 5: 6: require "cgi" 7: 8: def main() 10: @cgi = CGI.new() 11: print_header() 12: print_content() 13: exit( 0 ) 14: end 15: 16: def print_header() 17: printf("Content-Type: text/html\n") 18: printf("\n") 19: end 20: 21: def print_content() 22: printf("<HTML><HEAD></HEAD><BODY><PRE>\n") 23: printf("request_method: %s\n",e(@cgi.request_method)) 24: printf("script_name: %s\n",e(@cgi.script_name)) 25: printf("query_string: %s\n",e(@cgi.query_string)) 26: printf("content_length: %d\n",@cgi.content_length ? @cgi.content_length : 0 ) 27: qh = @cgi.keys 28: i = 0 29: qh.each { |name| 30: val = @cgi[name] 31: printf("qv[%d]: %s=%s \n",i,e(name),e(val) ) 32: i = i + 1 33: } 34: printf("</PRE></BODY></HTML>\n") 35: end 36: 37: def e( str ) 38: return( str == nil ? "(null)" : CGI::escapeHTML(str) ) 39: end 40: 41: main()
Ruby では、require で、必要なライブラリを読み込む。 def から end までがメソッドの定義(関数の定義)である。
main() では、CGI.new() により、CGI クラスのインスタンスを生成している。 その結果を @cgi という変数(インスタンス変数、mainの外でも使える)に保存 している。
このプログラムでは、main() という名前のメソッドを定義しているが、 main() というメソッドから実行が開始させるわけではない。メソッド定義で はないものは、即座に実行される。このプログラムは最後に main() を呼び出 す文がある。これを忘れると何も実行されない。
print_header()では、HTTP のヘッダのうち、Content-Type: 行だけを 出力している。
print_content() では、本文を出力している。
関数(メソッド) e() では、CGI ライブラリ (CGIクラス)の CGI::escapeHTML() を呼び出して、 クライアントから送られてきた「文字列」を 安全なものにして表示する。 たとえば、「<」は、「<」と変換している。こ れで、<SCRIPT> のような危険なスクリプトが送り込まれたとし ても「<SCRIPT>」と表示と表示されるだけで、スクリプト は実行されない。
@cgi に保存されたCGI クラスのインスタンスの request_method() メソッド を呼び出すと、"GET" か "POST" が返される。環境変数は、ハッシュ表 ENV に対して ENV['REQUEST_METHOD'] のようにしてもアクセスできるが、環境変 数を CGI クラスで変更してしまうこともあるようである。
@cgi.keys により、パラメタの一覧が配列の形で得られる。配列の各要素につ いて(qh.each)、パラメタ名を得て表示している。この例では、どんなパラメ タでも表示しているので、このようなループになっているが、通常の CGI プ ログラムでは、@cgi['パラメタ名'] のようにして、パラメタの値を文字列と して取り出すだけでよい。
op = @cgi['op'] val_s = @cgi['val']@cgi['パラメタ名']は、もし 'パラメタ名'のパラメタが設定されていなければ、 空文字列
""
を返す。
表示例:
実行例:
request_method: GET script_name: /~syspro/2024/2024-07-31/cgi-printarg-ruby.cgi query_string: lastname=name1&firstname=name2&lang=C&email=who%40dom content_length: 0 qv[0]: lastname=name1 qv[1]: firstname=name2 qv[2]: lang=C qv[3]: email=who@dom
request_method: POST script_name: /~syspro/2024/2024-07-31/cgi-printarg-ruby.cgi query_string: content_length: 53 qv[0]: lastname=name1 qv[1]: firstname=name2 qv[2]: lang=C qv[3]: email=who@dom
$ export REQUEST_METHOD=GET
$ export QUERY_STRING='lastname=name1&firstname=name2&lang=C&email=who%40dom'
$ ./cgi-printarg-ruby.cgi
Content-Type: text/html
<HTML><HEAD></HEAD><BODY><PRE>
request_method: GET
script_name: (null)
query_string: lastname=name1&firstname=name2&lang=C&email=who%40dom
content_length: 0
qv[0]: lastname=name1
qv[1]: firstname=name2
qv[2]: lang=C
qv[3]: email=who@dom
</PRE></BODY></HTML>
$
その他に標準入力からパラメタを与えてでデバッグすることもできる。
$ unset REQUEST_METHOD
$ unset QUERY_STRING
$ echo 'lastname=name1&firstname=name2&lang=C&email=who%40dom' | ./cgi-printarg-ruby.cgi
Content-Type: text/html
<HTML><HEAD></HEAD><BODY><PRE>
request_method: (null)
script_name: (null)
query_string: (null)
content_length: 0
qv[0]: lastname=name1
qv[1]: firstname=name2
qv[2]: lang=C
qv[3]: email=who@dom
</PRE></BODY></HTML>
$
外部のプログラムを実行する時には、execve() のようなシステムコールを使い、
かつ、限られたプログラムしか実行しないようにすると安全性が高くなる。ク
ライアントから送られてきた文字列をsystem() や popen() に渡してプログラ
ムを実行する時には、必ず検査する。特にシェルが解釈する特殊な文字
「| & ; && || `
」などが含
まれていた場合、意図しないプログラムが実行されることがある。
File *f; char cmd[BUFSIZE]; year_s = getparam(qc,qv,"year"); month_s = getparam(qc,qv,"month"); snprintf(cmd,BUFSIZE,"/usr/bin/cal %s %s", month_s, year_s ); f = poepn(cmd,"r"); fgets(line,sizeof(line),f);もし、year_s に
";"
や "|"
が含まれていたら、侵入される。
f = poepn("/usr/bin/cal 8 2024; cat /etc/passwd","r");
このような問題を防ぐには、次のようにすると良い。
Ruby の open() には、危険性がある。 C 言語のライブラリ関数 popen() と同じ動きをすることがある。
open("|cmd")
Ruby の注意すべき関数、式、クラス
Ruby でも fork() は使える。
Ruby の exec(), spawn() は、 コマンドの引数にシェルのメタキャラクタが含まれていれば、 シェルを経由して実行されることがある。 次の形式では、execve() で実行される(argsは配列)。
exec("/full/path/name", *args)
インタプリタなので、eval() にも注意する。 eval() は、Ruby の任意の式を評価できる。 system() 等の実行だけでなく、Ruby の変数もアクセスできる。
eval("system(\"ls\")") x = 10 eval("x=100") printf("%d\n",x)
Python の注意すべき関数、式、クラス
インタプリタなので、eval() や exec() にも注意する。 引数の文字列を評価・実行できる。
アンケートはTWINSから回答してください。
複数の教員が講義を担当している場合は、授業全体について回答して下さい。 各教員への意見・質問は最後の自由記載欄にお願いします。
なお、皆さんの評価が成績に影響することは一切ありません。 また、評価結果を教育の改善以外の目的に利用することはありませんし、 評価結果を公開する場合には個人を特定できるような情報は含めません。
締切は、8月29日です。 レポートを提出したら忘れないうちにすぐに提出すると良いでしょう。
レポートには、最初に脆弱生がある CGI プログラムを作成した年月日、 今回修正した場所、および、その修正箇所の説明をつけなさい。
ただし、脆弱性があるプログラムとしては、この科目で作成したプログラムは 使えないものとする。
レポートには、最初に脆弱生がある CGI プログラムを作成した年月日、 今回修正した場所、および、その修正箇所の説明をつけなさい。
ただし、脆弱性があるプログラムとしては、この科目で作成したプログラムは 使えないものとする。
次の CGI プログラムを シェルから実行 しなさい。
cgi-arg1arg2-ruby.txt
]
$ cp ~yas/syspro/www/cgi-arg1arg2-ruby.cgi .
$ export REQUEST_METHOD=GET
$ export QUERY_STRING='arg1=10&arg2=20'
$ ./cgi-arg1arg2-ruby.cgi
Content-Type: text/html
<HTML><HEAD></HEAD><BODY><PRE>
arg1: [10]
arg2: [20]
</PRE></BODY></HTML>
$
自宅の PC で実行する時には、 一般のインタプリタ で説明したように、1行目のパス名を変更しなさい。 ruby コマンドのパス名は、次のコマンドで表示される。
$ which ruby
「./cgi-arg1arg2-ruby.cgi
」で実行する代りに、
ruby コマンドにスクリプトのファイル名を与えて実行する方法もある。
$ ruby cgi-arg1arg2-ruby.cgi
次のようにパラメタを設定して実行してみなさい。
余裕があれば、REQUEST_METHOD=POST についても、同様に実行してみなさい。
余裕があれば、フォームを定義し、何かデータを送ってみなさい。 coins で CGI を実行する場合、CGI の実行形式を Web サーバ (http://www.coins.tsukuba.ac.jp) に ssh でログインした上で作成すること。
https://www.coins.tsukuba.ac.jp/~syspro/2024/2024-07-31/cgi-arg1arg2-ruby.cgi
たとえば、次のような記述を含む HTML ファイルを作成し、 ~/public_html/ 以下に置く。
<FORM ACTION="https://www.coins.tsukuba.ac.jp/~syspro/2024/2024-07-31/cgi-arg1arg2-ruby.cgi" method="get"> arg1: <INPUT type="text" name="arg1"> arg2: <INPUT type="text" name="arg2"> <INPUT type="submit"> <INPUT type="reset"> </FORM>
file-counter-ruby.txt
]
CGIによるカウンタ を Ruby 言語で書き直しなさい。ただし、次のことを実装しなくてもよい。
ヒント:
cgi-opval.cのC言語の関数getparam()
の代わりに Ruby 言語の @cgi["val"]
が使える。
@cgi["val"]
は、もし "val"
のパラメタが設定されていな
ければ、空文字列 ""
を返す。
ヒント:C 言語の strtol() のように、文字列から整数値を得るには、Ruby で は、to_i() を使って次のように行う方法がある。
val_s = "100" val = val_s.to_i()to_i() は、文字列として "100xx" のように、数字以外が 現れると、それより前の数字だけから計算した値を返す。 たとえば、"100xx".to_i() は、整数 100 を返す。 文字列に数字が一切表れない時には、0 を返す。 本日の課題では、to_i() の動作に従って回答しても良い。
この課題では、
CGIによるカウンタ
と同様に、作成したプログラムを
シェルから実行
して動作を確認しなさい。
この時、単にカウンタの値を表示するだけでなく、CGI として必須の行(Content-Type: 行
や空行) を含んでいること。
結果を HTML で返す場合、ブラウザで表示できるような HTML であること。
cgi-arg1arg2-python.txt
] 2024/07/31 13:00修正
2024/07/31 13:00: このスクリプトを端末で実行すると、次のような警告が出ます。
./cgi-printarg-python.cgi:6: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
次のようなコードを追加すると、警告を抑止できます。
import warnings warnings.filterwarnings("ignore", category=DeprecationWarning)上のコードは修正済みです。
file-counter-python.txt
]
CGIによるカウンタ を Python 言語で書き直しなさい。 練習問題(1005) と同じことを、Python 言語を用いて行いなさい。
$ cal
July 2024
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
$
CGI プログラムを実行した月のカレンダーを表示しなさい。固定した表示する だけなら、CGI の意味はない。余計な表示は省略すること。
$ ./a.out
Content-Type: text/html
<HTML><HEAD></HEAD><BODY><PRE>
July 2024
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
</PRE></BODY></HTML>
$
$ mkdir ~/public_html/syspro-cgi-examples
$ cp a.out ~/public_html/syspro-cgi-examples/cal-one.cgi
$ open https://www.coins.tsukuba.ac.jp/~ログイン名/syspro-cgi-examples/calc-one.cgi
<FORM ACTION="https://www.coins.tsukuba.ac.jp/~ログイン名/syspro-cgi-examples/calc-one.cgi" method="get"> <INPUT type="submit"> </FORM>
$ cal 8 2024
August 2024
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
$
この機能を利用して、Web ブラウザから送られた年月のカレンダーを表示する
CGI プログラムを作成しなさい。
char *year_s,*month_s; year_s = getparam(qc,qv,"year"); month_s = getparam(qc,qv,"month");getparam() は、 cgi-opval.cgiのソースコード に含まれている。
$ export REQUEST_METHOD=GET
$ export QUERY_STRING='year=2024&month=8'
$ ./a.out
Content-Type: text/html
<HTML><HEAD></HEAD><BODY><PRE>
August 2024
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
</PRE></BODY></HTML>
$
なお、一度設定した環境変数の値は、シェルを終了するまで残っている。
a.out を実行するたびに設定する必要はない。
レポートには、次の結果を含めなさい。
$ mkdir ~/public_html/syspro-cgi-examples
$ cp a.out ~/public_html/syspro-cgi-examples/cal.cgi
https://www.coins.tsukuba.ac.jp/~ログイン名/syspro-cgi-examples/cal.cgi?year=2024&month=8
"year=2024&month=8"のように送るようなフォームを含むHTML ファイルを作成する。
この課題では、フォームを含む HTML ファイルを作成し、 CGIとして実行し、その結果をレポート含めなさい。 その結果としては、 アクセスログ を含めなさい。
注意: CGI のパラメタは、最初は、文字列で受け取り、最終的に cal コマンドには文 字列で渡す。この時に、年月日としては不適切なものがクライアントから渡さ れる可能性がある。不適切なものが渡された場合には、エラー・メッセージを 表示しなさい。また、不正なパラメタで cal コマンドは実行しないようにしなさい。
練習問題(1011) と同じ動作をするプログラムを Ruby で書きなさい。
クライアントから不正なパラメタから与えられた場合には、 エラー・メッセージをクライアントに返しなさい。 レポートには、不正なパラメタが与えられた場合の実行結果を含めなさい。
この課題では、慎重に 外部のプログラムを実行 しなさい。 シェルを経由しないで /usr/bin/cal を実行しなさい。 それ以外のプログラムを実行してはならない。
この課題では、フォームを含む HTML ファイルを作成し、 CGIとして実行し、その結果をレポート含めなさい。 その結果としては、 アクセスログ を含めなさい。
練習問題(1011) と同じ動作をするプログラムを Python で書きなさい。
クライアントから不正なパラメタから与えられた場合には、 エラー・メッセージをクライアントに返しなさい。 レポートには、不正なパラメタが与えられた場合の実行結果を含めなさい。
この課題では、慎重に 外部のプログラムを実行 しなさい。 シェルを経由しないで /usr/bin/cal を実行しなさい。 それ以外のプログラムを実行してはならない。
この課題では、フォームを含む HTML ファイルを作成し、 CGIとして実行し、その結果をレポート含めなさい。 その結果としては、 アクセスログ を含めなさい。
ファイルとして保存する場合、CGIで不正なファイル名のファイルが作成されないようにしなさい。 永続的なハッシュ表を用いる場合、CGIで不正なキーが作成されないようにしなさい。
ヒント: Ruby では CGI オブジェクトの params() メソッドを使い、配列の形で得る。 Python では、getfirst() ではなく getlist() を使う。
ヒント: Ruby の CGI オブジェクトでは、ファイルの場合、StringIO クラスのオブジェ クトになる。IOクラスのオブジェクトのように、read(), each(), gets(), readline() といったメソッドが使える。