Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
MTで学ぶセキュアプログラミング
MT  Tokyo  2014  August
junnama@alfasado.jp
何のために?
•サイトの改ざんを防ぐために  
•クライアントのセキュリティ要件を
満たすために  
•被害リスクをできるだけ少なくする
ために
何のために、誰が?
•セキュリティコンサルタントが  
•プログラマが  
•デザイナが  
•ディレクターが
何を?
•MTMLテンプレートを  
•Movable  Typeそのものを  
•MTプラグインを  
•MTベースのウェブサイトを
イントロダクション
<Tweet禁⽌止>
⼤大⼈人の事情につき削除
本題
</Tweet禁⽌止>
例例  :  PHPを出⼒力力するテンプレート
PHPを出⼒力力するテンプレート
これは果たして脆弱性か?
何をされたくないか
•情報の漏漏洩(権限のない情報
へのアクセス)  
•権限昇格=権限を越えた操作  
•情報の書き換え、削除
性善説か?  性悪説か?
攻撃するのは誰?
•悪意の第三者による外部から
のアタック  
•内部犯⾏行行(元社員、コミュニ
ティユーザー)  
•内部(犯⾏行行ではないが)誘発=>
正規のユーザーに踏ませる
そこまで許可した覚えはない。
いや、だって、できるんだ
から。。。
Vs.
この場合、どちらが悪いのか?
はともかく、セキュリティ監査
では、アウト。
基本、性悪説に基づく。
<MTEntryBody
replace=”<?”,””>
完璧に防げるか?  
(程度度問題→やらないより、まし)
AllowPHPScript 0
PowerCMS(DynamicMTMLでは)...
<MTStripPHP>
<MTEntryBody>
</MTStripPHP>
PowerCMS(DynamicMTMLでは)...
function strip_php( $source ) {!
$tokens = token_get_all( $source );!
$res = '';!
$inphp = FALSE;!
foreach ( $tokens as $t...
<MTEntryBody
replace=”<?”,””>
でも、やらないより遥かにまし
主なもの
•XSS  =  Cross  Site  Scripting  
•CSRF  =  Cross  site  request  
forgeries  
•SQL  (OS  Command)  Injection  
•Dire...
例例  :  検索索結果テンプレート
例例  :  検索索結果テンプレート
例例  :  検索索結果テンプレート
例例  :  検索索結果テンプレート
例例  :  検索索結果テンプレート
sub load_core_tags {!
require MT::Template::Context;!
return {!
function => {!
SearchString => &_hdlr_s...
例例  :  検索索結果テンプレート
sub prepare_context {!
my $app = shift;!
my $q = $app->param;!
...!
if ( my $str = $app->{search_string...
あまり宜しくない!(きっぱり)
例例  :  検索索結果テンプレート
...!
!
sub context_script {!
my ( $ctx, $args, $cond ) = @_;!
!
my $search_string!
= decode_html($ctx->...
•どこでエスケープ済みなのか、
わからなくなるぞ?  
•エンコード済みのクエリを渡さ
れたらおかしくならんか?
統⼀一されていないので、
責任が曖昧(忘れちゃう)
わからなくなるから...
わからなくなるから...
⼊入⼒力力値のエスケープは、  
テンプレート出⼒力力時に統⼀一
次
$q = $_GET[‘search’];!
$sql = “SELECT FROM
mt_entry WHERE!
mt_entry.entry_title LIKE %
${q}%”
例例  :  PHPによる実装
APIやORマッパを使え
my $app = MT->instance;!
my $q = $app->param(‘search’);!
my @entries = MT-
>model(‘entry’)!
->load( {!
title => { like => ...
$app = $ctx-
>stash(‘bootstrapper’);!
$q = $app->param(‘search’);!
$entries = $app->!
load(‘entry’,!
array( ‘title’ => !
a...
var q = jQuery('#search').value;!
var params = {!
search: q,!
searchFields: "title,body",!
};!
api.listEntries(siteId, par...
何かあったらメーカーのせいw
ユーザーの⼊入⼒力力を信⽤用しない!
そもそも
次
applications:!
cms:!
menus:!
page:page_foo:!
label: Foo!
order: 1000!
mode: page_foo!
permission: manage_pages!
view:!
- b...
例例  :  Pluginでのメソッドの拡張
methods:!
page_foo: $Foo::Foo::CMS:: page_foo!
package Foo::CMS!
!
sub page_foo {!
my $app = shift;...
例例  :  Pluginでのメソッドの拡張
短縮URLでもメールで送り
つけてやれ!
やっちゃえ!(*)
脱線  :  管理理画⾯面にBasic認証かけても、正規
ユーザー攻撃タイプには意味がないよね。
新規作成
編集
削除
例例  :  Pluginで独⾃自オブジェクト
え?
sub  save  {  
        my  $app    =  shift;  
        my  $q        =  $app-‐‑‒>param;  
        my  $type  =  $q-‐‑‒>par...
対策
程度度問題=読み出されるだけより、改ざ
んされるほうが  い・や・だ。
ちょっと脱線。何故ここだけ対策を?
セキュリティにおいて、「程度度問題」
はいつもつきまとう。
但し、前提は事情に
よって変わる
例例えば、個⼈人情報。  
流流出も改ざんもどっちもどっち
改めて対策
package  MT::App::CMS;
ホワイトリストではなくブラックリスト
なので、不不要なものは塞塞いでおく
GETリクエストは弾く(気休めだが)
package Foo::CMS!
!
sub page_foo {!
my $app = shift;!
if ( $app->request_method ne “POST” ) { !
return ...
⼀一時トークンのチェック
package Foo::CMS!
!
sub page_foo {!
my $app = shift;!
if $app->validate_magic!
or return $app->permission_den...
⼀一時トークンのチェック
•magic_̲token=アクティブユーザーの
session情報  
•saveやdelete等の操作ではチェックを!  
•(但し)magic_̲tokenが無効もしくは空の
時、ID/Password⼊入⼒力力...
⼀一時トークンのチェック
•magic_̲token=アクティブユーザーの
session情報  
•saveやdelete等の操作ではチェックを!  
•(但し)magic_̲tokenが無効もしくは空の
時、ID/Password⼊入⼒力力...
でも
CSRFとしては、不不⼗十分ではないか?
mt.cgi?_̲_̲mode=save&_̲type=foo&title=Title...
クリックしちゃだめー!
悪意のURL
改善案
if $app->validate_magic(!
{ with_confirm!
=> { message =>!
ʻ‘FooをBarしようとしています。  
                                     ...
改善案(簡易易指定)
if $app->validate_magic!
( ʻ‘FooをBarしようとしています。宜しいですか?ʼ’ )!
or return $app->trans_error...!
}!
改善案(次に何が起こるのかを明⽰示する)
FooをBarしようとして  
います。宜しいですか?
これからはセキュリティだっ
て、UX重視だろ!
話しを戻します
package Foo::CMS!
!
sub page_foo {!
my $app = shift;!
my $perms = $app->permissions!
or return $app->permission_denied();!...
例例題
sub  some_̲action{  
        my  $app=  shift;  
        require  MT::Page;  
        my  $blog  =  app-‐‑‒>blog;  
      ...
1.パラメタidに数字以外のものが渡された場合  
2.パラメタidにpageオブジェクトではなく
entryオブジェクトのidが渡された場合  
3.パラメタidが空の場合  
4.パラメタidに現在のblogに属さないentry/
page...
sub  some_̲action{  
        my  $app=  shift;  
        require  MT::Page;  
        my  $blog  =  app-‐‑‒>blog;  
      ...
添削後
sub  some_̲action  {  
        my  $app  =  shift;  
        $app-‐‑‒>validate_̲magic(  ʻ‘FooをBarしてもよろしいですか?ʼ’  )  or  
  ...
       if  (!  $app-‐‑‒>can_̲do(  'manage_̲pages'  )  )  {  
                return  $app-‐‑‒>trans_̲error(  'Permission  ...
⼀一気に難易易度度あがりましたが...
結論論
まとめ
•セキュアプログラミングは性悪説  
•それでも程度度問題。何をやられない
ようにするか。何を優先するか(何
は、あきらめるか)  
•セキュリティにもUXの視点が必要
まとめ
•ユーザーの⼊入⼒力力を信⽤用しない  
•エスケープは出⼒力力時に統⼀一する  
•SQLを⾃自前で書くな。API使え  
•正規ユーザー攻撃型改ざん対策のた
めに、⼀一時トークンを使う
ありがとうございました。
MTで学ぶセキュアプログラミング@MT Tokyo
MTで学ぶセキュアプログラミング@MT Tokyo
MTで学ぶセキュアプログラミング@MT Tokyo
MTで学ぶセキュアプログラミング@MT Tokyo
MTで学ぶセキュアプログラミング@MT Tokyo
MTで学ぶセキュアプログラミング@MT Tokyo
MTで学ぶセキュアプログラミング@MT Tokyo
MTで学ぶセキュアプログラミング@MT Tokyo
Upcoming SlideShare
Loading in …5
×

MTで学ぶセキュアプログラミング@MT Tokyo

1,813 views

Published on

MT東京 8月 テーマセキュリティのセッション

Published in: Technology
  • Be the first to comment

MTで学ぶセキュアプログラミング@MT Tokyo

  1. 1. MTで学ぶセキュアプログラミング MT  Tokyo  2014  August junnama@alfasado.jp
  2. 2. 何のために? •サイトの改ざんを防ぐために   •クライアントのセキュリティ要件を 満たすために   •被害リスクをできるだけ少なくする ために
  3. 3. 何のために、誰が? •セキュリティコンサルタントが   •プログラマが   •デザイナが   •ディレクターが
  4. 4. 何を? •MTMLテンプレートを   •Movable  Typeそのものを   •MTプラグインを   •MTベースのウェブサイトを
  5. 5. イントロダクション <Tweet禁⽌止>
  6. 6. ⼤大⼈人の事情につき削除
  7. 7. 本題 </Tweet禁⽌止>
  8. 8. 例例  :  PHPを出⼒力力するテンプレート
  9. 9. PHPを出⼒力力するテンプレート
  10. 10. これは果たして脆弱性か?
  11. 11. 何をされたくないか •情報の漏漏洩(権限のない情報 へのアクセス)   •権限昇格=権限を越えた操作   •情報の書き換え、削除
  12. 12. 性善説か?  性悪説か?
  13. 13. 攻撃するのは誰? •悪意の第三者による外部から のアタック   •内部犯⾏行行(元社員、コミュニ ティユーザー)   •内部(犯⾏行行ではないが)誘発=> 正規のユーザーに踏ませる
  14. 14. そこまで許可した覚えはない。 いや、だって、できるんだ から。。。 Vs.
  15. 15. この場合、どちらが悪いのか? はともかく、セキュリティ監査 では、アウト。 基本、性悪説に基づく。
  16. 16. <MTEntryBody replace=”<?”,””>
  17. 17. 完璧に防げるか?   (程度度問題→やらないより、まし)
  18. 18. AllowPHPScript 0 PowerCMS(DynamicMTMLでは)...
  19. 19. <MTStripPHP> <MTEntryBody> </MTStripPHP> PowerCMS(DynamicMTMLでは)...
  20. 20. function strip_php( $source ) {! $tokens = token_get_all( $source );! $res = '';! $inphp = FALSE;! foreach ( $tokens as $token ) {! if ( is_string( $token ) ) {! $token = array( '', $token );! }! list( $id, $str ) = $token;! if (! $inphp ) {! if ( $id === T_OPEN_TAG or $id == T_OPEN $inphp = TRUE;! } else {! $res .= $str;! }! 厳密には、PHPはPHPで評価する
  21. 21. <MTEntryBody replace=”<?”,””> でも、やらないより遥かにまし
  22. 22. 主なもの •XSS  =  Cross  Site  Scripting   •CSRF  =  Cross  site  request   forgeries   •SQL  (OS  Command)  Injection   •Directory  traversal
  23. 23. 例例  :  検索索結果テンプレート
  24. 24. 例例  :  検索索結果テンプレート
  25. 25. 例例  :  検索索結果テンプレート
  26. 26. 例例  :  検索索結果テンプレート
  27. 27. 例例  :  検索索結果テンプレート sub load_core_tags {! require MT::Template::Context;! return {! function => {! SearchString => &_hdlr_search_string,! ...! ! sub _hdlr_search_string! { $_[0]->stash('search_string') || '' } package MT::Template::Context::Search;!
  28. 28. 例例  :  検索索結果テンプレート sub prepare_context {! my $app = shift;! my $q = $app->param;! ...! if ( my $str = $app->{search_string} ) {! $ctx->stash(! 'search_string', encode_html($str) );! } package MT::App::Search;! コード中でエスケープしてる
  29. 29. あまり宜しくない!(きっぱり)
  30. 30. 例例  :  検索索結果テンプレート ...! ! sub context_script {! my ( $ctx, $args, $cond ) = @_;! ! my $search_string! = decode_html($ctx->stash('search_string') package MT::Template::Context::Search;! わざわざ戻してんのかよ!
  31. 31. •どこでエスケープ済みなのか、 わからなくなるぞ?   •エンコード済みのクエリを渡さ れたらおかしくならんか?
  32. 32. 統⼀一されていないので、 責任が曖昧(忘れちゃう)
  33. 33. わからなくなるから...
  34. 34. わからなくなるから...
  35. 35. ⼊入⼒力力値のエスケープは、   テンプレート出⼒力力時に統⼀一
  36. 36.
  37. 37. $q = $_GET[‘search’];! $sql = “SELECT FROM mt_entry WHERE! mt_entry.entry_title LIKE % ${q}%” 例例  :  PHPによる実装
  38. 38. APIやORマッパを使え
  39. 39. my $app = MT->instance;! my $q = $app->param(‘search’);! my @entries = MT- >model(‘entry’)! ->load( {! title => { like => $q }, ! } ) 例例  :  Perlによる実装
  40. 40. $app = $ctx- >stash(‘bootstrapper’);! $q = $app->param(‘search’);! $entries = $app->! load(‘entry’,! array( ‘title’ => ! array( ‘like’ => $q ))); 例例  :  PHP(DynamicMTML)による実装
  41. 41. var q = jQuery('#search').value;! var params = {! search: q,! searchFields: "title,body",! };! api.listEntries(siteId, params, function(response) {! if (response.error) {! return;! }! 例例  :  JavaScriptによる実装
  42. 42. 何かあったらメーカーのせいw
  43. 43. ユーザーの⼊入⼒力力を信⽤用しない! そもそも
  44. 44.
  45. 45. applications:! cms:! menus:! page:page_foo:! label: Foo! order: 1000! mode: page_foo! permission: manage_pages! view:! - blog! - website! 例例  :  Pluginでのメソッドの拡張
  46. 46. 例例  :  Pluginでのメソッドの拡張 methods:! page_foo: $Foo::Foo::CMS:: page_foo! package Foo::CMS! ! sub page_foo {! my $app = shift;! # Do Something! <= え?! }!
  47. 47. 例例  :  Pluginでのメソッドの拡張 短縮URLでもメールで送り つけてやれ! やっちゃえ!(*)
  48. 48. 脱線  :  管理理画⾯面にBasic認証かけても、正規 ユーザー攻撃タイプには意味がないよね。
  49. 49. 新規作成 編集 削除 例例  :  Pluginで独⾃自オブジェクト
  50. 50. え?
  51. 51. sub  save  {          my  $app    =  shift;          my  $q        =  $app-‐‑‒>param;          my  $type  =  $q-‐‑‒>param('_̲type');          my  $save_̲mode  =  'save_̲'  .  $type;          if  (  my  $hdlrs  =  $app-‐‑‒>handlers_̲for_̲mode($save_̲mode)  )  {                  return  $app-‐‑‒>forward($save_̲mode);}          my  $id  =  $q-‐‑‒>param('id');          $app-‐‑‒>validate_̲magic()  or  return;          my  $author  =  $app-‐‑‒>user;          my  $perms  =  $app-‐‑‒>permissions;          if  (  !$author-‐‑‒>is_̲superuser  )  {                  if  (  (  $type  ne  'author'  )  &&  (  $type  ne  'template'  )  ){                          return  return  $app-‐‑‒>permission_̲denied()  if  !$perms  &&  $id;                  }                  $app-‐‑‒>run_̲callbacks(  'cms_̲save_̲permission_̲filter.'  .  $type,                  $app,  $id  )  ||  return  $app-‐‑‒>permission_̲denied();          }   #以下、保存 MT::CMS::Common::save(⼀一部省省略略) magic_̲tokenを チェック save_̲fooメソッドが定義され ているときはそちらへforward システム管理理者の場 合、ここはスルー コールバックcms_̲save_̲permission_̲filter.fooが1以外を返すと権限エラー
  52. 52. 対策
  53. 53. 程度度問題=読み出されるだけより、改ざ んされるほうが  い・や・だ。 ちょっと脱線。何故ここだけ対策を? セキュリティにおいて、「程度度問題」 はいつもつきまとう。
  54. 54. 但し、前提は事情に よって変わる 例例えば、個⼈人情報。   流流出も改ざんもどっちもどっち
  55. 55. 改めて対策
  56. 56. package  MT::App::CMS; ホワイトリストではなくブラックリスト なので、不不要なものは塞塞いでおく
  57. 57. GETリクエストは弾く(気休めだが) package Foo::CMS! ! sub page_foo {! my $app = shift;! if ( $app->request_method ne “POST” ) { ! return $app->permission_denied();! }! #Do Something! } POSTしか受け付けない
  58. 58. ⼀一時トークンのチェック package Foo::CMS! ! sub page_foo {! my $app = shift;! if $app->validate_magic! or return $app->permission_denied();! }! #Do Something! } magic_̲tokenパラメタをチェック
  59. 59. ⼀一時トークンのチェック •magic_̲token=アクティブユーザーの session情報   •saveやdelete等の操作ではチェックを!   •(但し)magic_̲tokenが無効もしくは空の 時、ID/Password⼊入⼒力力画⾯面を表⽰示   •この時↑deleteメソッド以外ではパラメ タが引き継がれる
  60. 60. ⼀一時トークンのチェック •magic_̲token=アクティブユーザーの session情報   •saveやdelete等の操作ではチェックを!   •(但し)magic_̲tokenが無効もしくは空の 時、ID/Password⼊入⼒力力画⾯面を表⽰示   •この時↑deleteメソッド以外ではパラメ タが引き継がれる
  61. 61. でも
  62. 62. CSRFとしては、不不⼗十分ではないか? mt.cgi?_̲_̲mode=save&_̲type=foo&title=Title... クリックしちゃだめー! 悪意のURL
  63. 63. 改善案 if $app->validate_magic(! { with_confirm! => { message =>! ʻ‘FooをBarしようとしています。                                                      宜しいですか?ʼ’,! icon => ‘CAUTION’! } } )! or return $app->trans_error...! }!
  64. 64. 改善案(簡易易指定) if $app->validate_magic! ( ʻ‘FooをBarしようとしています。宜しいですか?ʼ’ )! or return $app->trans_error...! }!
  65. 65. 改善案(次に何が起こるのかを明⽰示する) FooをBarしようとして   います。宜しいですか?
  66. 66. これからはセキュリティだっ て、UX重視だろ!
  67. 67. 話しを戻します
  68. 68. package Foo::CMS! ! sub page_foo {! my $app = shift;! my $perms = $app->permissions! or return $app->permission_denied();! return $app->permission_denied()! unless $perms! ->can_do('edit_all_pages');! #Do Something! } ちゃんと権限をチェック +更更新が必要なものは権限をチェック
  69. 69. 例例題
  70. 70. sub  some_̲action{          my  $app=  shift;          require  MT::Page;          my  $blog  =  app-‐‑‒>blog;          my  $page  =  MT::Page-‐‑‒>load(  $app-‐‑‒>param(  'id'  )  );          if  (!  $page  )  {                  return  $app-‐‑‒>translate(  'Invalid  Page  ID:[_̲1].',  $app-‐‑‒>param(  'id'  )  );          }          my  $perm  =  $app-‐‑‒>user-‐‑‒>is_̲superuser;          if  (!  $perm  )  {                  $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $blog-‐‑‒>id  )-‐‑‒>can_̲administer_̲website                $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $blog-‐‑‒>id  )-‐‑‒>can_̲administer_̲blog                                              unless  $perm;                  $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $blog-‐‑‒>id  )-‐‑‒>can_̲manage_̲pages                  unless  $perm;          }          if  (!  $perm  )  {                  return  $app-‐‑‒>translate(  'Permission  denied.'  );          }          #  この後、$pageへの処理理}
  71. 71. 1.パラメタidに数字以外のものが渡された場合   2.パラメタidにpageオブジェクトではなく entryオブジェクトのidが渡された場合   3.パラメタidが空の場合   4.パラメタidに現在のblogに属さないentry/ pageのidが渡された場合 考えておかなければならないケース
  72. 72. sub  some_̲action{          my  $app=  shift;          require  MT::Page;          my  $blog  =  app-‐‑‒>blog;          my  $page  =  MT::Page-‐‑‒>load(  $app-‐‑‒>param(  'id'  )  );          if  (!  $page  )  {                  return  $app-‐‑‒>translate(  'Invalid  Page  ID:[_̲1].',  $app-‐‑‒>param(  'id'  )  );          }          my  $perm  =  $app-‐‑‒>user-‐‑‒>is_̲superuser;          if  (!  $perm  )  {                  $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $blog-‐‑‒>id  )-‐‑‒>can_̲administer_̲website                $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $blog-‐‑‒>id  )-‐‑‒>can_̲administer_̲blog                                              unless  $perm;                  $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $blog-‐‑‒>id  )-‐‑‒>can_̲manage_̲pages                  unless  $perm;          }          if  (!  $perm  )  {                  return  $app-‐‑‒>translate(  'Permission  denied.'  );          }          #  この後、$pageへの処理理} mt.cgi?_̲_̲mode=some_̲action&id= <script>alert('do')</script> id=1&blog_̲id=3   ↑   id:1のpageのblog_̲id が3である保証は? idが空だったら?もしくはEntryのIDが渡されたら? てか、テンプレート エンジン使え!
  73. 73. 添削後
  74. 74. sub  some_̲action  {          my  $app  =  shift;          $app-‐‑‒>validate_̲magic(  ʻ‘FooをBarしてもよろしいですか?ʼ’  )  or                  return  $app-‐‑‒>trans_̲error(  'Permission  denied.'  );          require  MT::Page;          my  $page;          if  (!  $app-‐‑‒>param(  'id'  )  ||                  (!  $page  =  MT::Page-‐‑‒>load(  $app-‐‑‒>param(  'id'  )  )  )  {                  return  $app-‐‑‒>trans_̲error(  'Invalid  Page  ID:'[_̲1]'',                                                                MT::Util::encode_̲html(  $app-‐‑‒>param(  'id'  )  )  );          }          if  (  $page-‐‑‒>class  ne  'page'  )  {                  return  $app-‐‑‒>trans_̲error(  'Invalid  Class:'[_̲1]'',  $page-‐‑‒>class  );          }          #  permission  check  case  1          if  (  $app-‐‑‒>blog-‐‑‒>id  !=  $page-‐‑‒>blog_̲id  )  {                  return  $app-‐‑‒>trans_̲error(  'Invalid  BlogID:'[_̲1]'',                                                                MT::Util::encode_̲html(  $app-‐‑‒>blog-‐‑‒>id  )  );          }  #  続く   操作を伴う場合最初にmagic_̲tokenをチェック 渡された値をそのまま表⽰示する場合、エスケープ Entryでないかチェック 違うブログIDに属するもので ないかチェック(※) ※システムスコープやウェブサイトスコープの場合はあり得るケース てか、テンプレート エンジン使え!
  75. 75.        if  (!  $app-‐‑‒>can_̲do(  'manage_̲pages'  )  )  {                  return  $app-‐‑‒>trans_̲error(  'Permission  denied.'  );          }          #  or  case  2          my  $perm  =  $app-‐‑‒>user-‐‑‒>is_̲superuser;            if  (!  $perm  )  {                  $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $page-‐‑‒>blog_̲id  )-‐‑‒>   can_̲administer_̲website;                  $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $page-‐‑‒>blog_̲id  )-‐‑‒>   can_̲administer_̲blog  unless  $perm;                  $perm  =  $app-‐‑‒>user-‐‑‒>permissions(  $page-‐‑‒>blog_̲id  )-‐‑‒>   can_̲manage_̲pages  unless  $perm;          }          if  (!  $perm  )  {                  return  $app-‐‑‒>trans_̲error(  'Permission  denied.'  );          }          if  (!  $app-‐‑‒>run_̲callbacks(  'cms_̲save_̲permission_̲filter.page'  $app,  $page  )  {                return  $app-‐‑‒>trans_̲error(  'Permission  denied.'  );          }          #  Do  Something.} $blog-‐‑‒>idではなく$page-‐‑‒>blog_̲idでチェック コールバックをすり 抜けないようにする
  76. 76. ⼀一気に難易易度度あがりましたが...
  77. 77. 結論論
  78. 78. まとめ •セキュアプログラミングは性悪説   •それでも程度度問題。何をやられない ようにするか。何を優先するか(何 は、あきらめるか)   •セキュリティにもUXの視点が必要
  79. 79. まとめ •ユーザーの⼊入⼒力力を信⽤用しない   •エスケープは出⼒力力時に統⼀一する   •SQLを⾃自前で書くな。API使え   •正規ユーザー攻撃型改ざん対策のた めに、⼀一時トークンを使う
  80. 80. ありがとうございました。

×