Category::Plugin

ref.inc.php拡張。画像CGIを<img />タグに置くためのimgオプション

  • ページ: BugTrack
  • 投稿者: sha
  • 優先順位: 低
  • 状態: 完了
  • カテゴリー: 欲しいプラグイン
  • 投稿日: 2003-09-04 (木) 00:32:38
  • バージョン: 1.4
  • リリース予定バージョン: 1.5.2

メッセージ

現在、セキュリティホールにならないように拡張子が画像を示さないもの(画像CGI等)をref.inc.phpで<img />タグを出力しないようになっているかと思いますが、下記の動作を行うことによって許容することはできますでしょうか?

  1. refオプションにimgを指定すると、引数のURLに対してhttp_request(URL,'HEAD')を送信。受信データのヘッダでContent-Typeが画像を示していれば、<img />タグを出力する。→1回の表示につき、CGIが2回叩かれてしまう。また、リクエスト先によってContent-Typeを変化させることさえ可能(例えばPukiWiki-officialからのアクセスには 画像の、それ以外のサイトには画像でないものに)なので悪意のあるCGI(プログラム)に対しては無力
  2. http_requestでキャッシュに保存して、ヘッダーのContent-Typeでキャッシュのファイルの表示方法を選択する

    重いかもしれませんが、それでも指定できた方がありがたい場合もありますので。「official:欲しいプラグイン/51」ご参照。


  • こんな感じ。下記の変更を加えると出来たようです。やってみて気づきましたが、この方法だと1回表示する毎に、http_request()と<img src=... />で2回アクセスしてしまうんですね。そりゃそうか。'HEAD'メソッドといえども、CGIが動作して画像を生成してからでないとheaderが送信できないから当然と言えば当然か。-- sha 2003-09-04 (木) 19:57:53
*** ref.inc.php-119	Thu Sep  4 15:03:33 2003
--- ref.inc.php	Thu Sep  4 19:55:42 2003
***************
*** 34,35 ****
--- 34,37 ----
  画像を展開しない
+ -img~
+ HEADメソッドでContent-Typeを確認
  -zoom~
***************
*** 157,158 ****
--- 159,161 ----
  		'noimg'  => FALSE, // 画像を展開しない
+ 		'img'    => FALSE, // 画像のContent-Typeを確認
  		'zoom'   => FALSE, // 縦横比を保持する
***************
*** 193,195 ****
  		
! 		$is_image = (!$params['noimg'] and preg_match("/\. (gif|png|jpe?g)$/i",$name));
 		if (REF_URL_GETIMAGESIZE and $is_image and (bool)ini_get ('allow_url_fopen'))
--- 196,199 ----
  		
! 		$is_image = (!$params['noimg'] and preg_match("/\. (gif|png|jpe?g)$/i",$name)) || 
!                          ($params['img'] and plugin_ref_is_type_image($name));
  		if (REF_URL_GETIMAGESIZE and $is_image and (bool)ini_get ('allow_url_fopen'))
***************
*** 376,377 ****
--- 380,395 ----
 	$params['_args'][] = $val;
+ }
+ // HEADメソッドでContent-Type確認
+ function plugin_ref_is_type_image($url){
+ 	$resp = http_request($url,'HEAD');
+ 	if ( (integer)($resp['rc'] / 100) != 2 ) return FALSE;
+ 	$lines = explode("\r\n",$resp['header']);
+ 	foreach ( $lines as $line ){
+ 		if ( preg_match('/^Content-Type\:\s*image\/(gif|png|jpe?g)\s*$/i', $line) ){
+ 			return TRUE;
+ 		}
+ 	}
+ 	return FALSE;
 }
  • やはり2回アクセスはなるべくなら避けたいところ。何かいい手はないものでしょうか?http_requestでキャッシュに保存して、ヘッダーのContent-Typeでキャッシュのファイルの表示方法を選択する、という方法なら1回で済みそうです。キャッシュをうまく使う方法ってどうすればよいでしょうか? -- sha 2003-09-04 (木) 21:38:32
  • ファイルに一旦蓄えて、1回表示したらそのファイルを削除するようにしてみました。なかなかうまく動いているようです。例えばこんな方法で、画像CGIへアクセスできる機能を正式版に実装していただければ幸いです。これ→「fileref.inc.php

    ところで、バイナリの画像データへアクセスする必要からproxy.inc.phphttp_request()の一部も変更する必要がありました。 -- sha 2003-09-06 (土) 12:30:55

*** proxy.php-102	Sat Sep 06 12:16:38 2003
--- proxy.php	Sat Sep 06 12:22:22 2003
***************
*** 85,87 ****
  	{
! 		$response .= fgets($fp,4096);
  	}
--- 85,87 ----
  	{
! 		$response .= fread($fp,4096);
  	}
*** ref.inc.php-119	Sat Sep 06 12:14:34 2003
--- ref.inc.php	Sat Sep 06 12:11:14 2003
***************
*** 5,7 ****
  // $Id: ref.inc.php,v 1.19 2003/06/30 05:06:48 arino Exp $
! //
  
--- 5,7 ----
  // $Id: ref.inc.php,v 1.19 2003/06/30 05:06:48 arino Exp $
! // modified by sha 2003/09/06 12:09:00
  
***************
*** 34,35 ****
--- 34,37 ----
  画像を展開しない
+ -img~
+ ヘッダーのContent-Typeで画像を確認
  -zoom~
***************
*** 157,158 ****
--- 159,161 ----
  		'noimg'  => FALSE, // 画像を展開しない
+ 		'img'    => FALSE, // Content-Typeで画像を確認
  		'zoom'   => FALSE, // 縦横比を保持する
***************
*** 194,195 ****
--- 197,208 ----
  		$is_image = (!$params['noimg'] and  preg_match("/\.(gif|png|jpe?g)$/i",$name));
+ 		if ( !$is_image and $params['img'] ){
+ 			$ret = plugin_ref_getimage($name,$page);
+ 			if ( $ret !== FALSE ) {
+ 				list($ctype,$num,$md5) = $ret;
+ 				$url = $script.'?plugin=ref&amp;refimg_no='.rawurlencode($num).
+       '&amp;page='.rawurlencode($page).'&amp;ctype='.rawurlencode($ctype).'&amp;md5='.rawurlencode($md5);
+ 				$url2 = '';
+ 				$is_image = TRUE;
+ 			}
+ 		}
  		if (REF_URL_GETIMAGESIZE and $is_image and (bool)ini_get('allow_url_fopen'))
***************
*** 376,377 ****
--- 389,441 ----
  	$params['_args'][] = $val;
+ }
+ // Content-Typedで画像を確認
+ function plugin_ref_getimage($url,$page){
+ 	global $script;
+ 	$resp = http_request($url);
+ 	if ( (integer)($resp['rc'] / 100) != 2 ) return FALSE;
+ 	$lines = explode("\r\n",$resp['header']);
+ 	foreach ( $lines as $line ){
+ 		if ( preg_match('/^Content-Type\:\s*image\/(gif|png|jpe?g)\s*$/i',$line,$match)){
+ 			$md5 = md5($resp['data']);
+ 			$num = plugin_ref_writeimage($url,$page,$resp['data']);
+ 			return array($match[1],$num,$md5);
+ 		}
+ 	}
+ 	return FALSE;
+ }
+ function plugin_ref_writeimage($url,$page,$data){
+ 	list($num,$file) = plugin_ref_make_filename($url,$page);
+ 	$fp = fopen($file,'wb')	or die_message('cannot write '.$file);
+ 	flock($fp,LOCK_EX);
+ 	fwrite($fp,$data);
+     fflush($fp);
+ 	flock($fp,LOCK_UN);
+ 	fclose($fp);
+ 	return $num;
+ }
+ function plugin_ref_make_filename($url,$page){
+ 	$num = 0;
+ 	do {
+ 		$num ++;
+ 		$id = encode($page).'_'. $num;
+ 		$file = CACHE_DIR . $id . '.refimg';
+ 	} while( file_exists($file) );
+ 	return array($num,$file);
+ }
+ function plugin_ref_action(){
+ 	global $vars;
+ 	if ( !array_key_exists('refimg_no',$vars) or !array_key_exists('md5',$vars) or 
+ 		 !array_key_exists('page',$vars) or !array_key_exists('ctype',$vars) ) {
+ 		return array('msg'=>'Error', 'body'=>'cannot be executed as command.');
+ 	}
+ 	$oldmd5  = $vars['md5'];
+ 	$refimg_no = $vars['refimg_no'] + 0;
+ 	$file = CACHE_DIR . encode($vars['page']) .'_'. $refimg_no .'.refimg';
+ 	$ctype = $vars['ctype'];
+ 	if ( file_exists($file) and $oldmd5 == md5_file($file) ) {
+ 		header('Content-Type: image/' . trim($ctype));
+ 		@readfile($file);
+ 		@unlink($file);
+ 	}
+ 	die;
  }
  • そもそも、is_url() が真の場合には、(拡張子を限定せず) img タグを許可しても OK な気がするんですが。。。 -- masao 2003-09-06 (土) 20:19:06
    • 画像じゃないときに壊れていることを示すxアイコンを表示したくないからではないでしょうか?refは画像でなくても参照できることが売りですので。 -- sha 2003-09-11 (木) 18:09:19
    • えっと、すみません。意図が伝わらなかったようで。。。上記のパッチの処理のうち、Content-Type を確認する処理は不要ではないか。つまり、「 img オプションが指定された場合には、(Content-Type を考慮せず) img タグを表示して OK だと思います。」ということが聞いてみたいのですが…。 -- masao 2003-09-12 (金) 14:06:26
    • なるほど。imgオプションを指定したときには、#refの設置者に正常に表示されているか否かを判断してもらうということですね。設置者が面倒を見るなら、Content-Typeどころか拡張子すら見る必要はなさそうですが、そこまで任せてしまっていいものなんでしょうか。いずれにしても、確かに私の上の修正は大げさすぎる気はしていました。 -- sha 2003-09-13 (土) 15:20:15
  • メッセージに、セキュリティホールにならないように拡張子が画像を示さないものとあったので、いまさら何を(拡張子で判別ということですよぉ)と思ってソースを見てみましたが、attach で対応した内容が ref に生かされていない。ということだったんですね。でも、まだ img もありますから、忘れずに対応しておくのかなぁ? -- upk
  • アフィリエイトのバナーを貼りたいがためにいろいろさがして、ここにたどり着きました。~これを,1.4.5にはめ込みたいのですが、どうしたらいいでしょうか? -- ひさ(なべ)? 2005-03-17 (木) 17:53:06
  • ご回答ありがとうございます。自分自身で使えば、それらのプラグインでもいいのですが、ほかの利用者にも貼ってもらいたいんです。それで、ちょっと悩んでいるのです。 -- ひさ(なべ)? 2005-03-20 (日) 12:09:15
  • BugTrack2/69 -- henoheno 2005-05-18 (水) 22:43:54
  • 元発言のコメントにツッコミ追加。どこからのリクエストなのかによってContent-Typeを変化させることさえ可能(例えば攻撃URIを埋め込んだサイトからのアクセス*1には 画像の、それ以外のサイトには画像でないものに)なので、悪意のある「リモート」ホスト(CGIプログラムや、それを隠蔽したURI)に対してはContent-Typeの事前チェックは無力です(穴があるということです)。 BugTrack2/69 も参照あれ。-- henoheno 2005-05-18 (水) 23:09:50
  • BugTrack/2465 imgプラグインが拡張子に関わらずimgタグで画像を表示するようになりました。refプラグインの動作は変わっていませんが、完了とします -- umorigu 2019-02-02 (土) 20:20:36


*1 上で言う「確認のためのリモートアクセス」のIPアドレスとそのネットワークアドレスはどうしても固定的になるので判別可能

添付ファイル: fileref.inc.php 1017件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-02-02 (土) 20:58:38
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u7. HTML convert time: 0.228 sec.

OSDN