2013年2月24日日曜日

Oracle で暗号化

以前、Oracle 上で暗号化をしなければいけない案件があり、ちょっと苦労したのでメモ。トライしたのは、SHA1のハッシュ化です。

まず、DBMS_CRYPTOパッケージの HASH 関数を利用するために、Oracle アカウントに権限を設定します。

grant execute on DBMS_CRYPTO to MYACCOUNT;

DBMS_CRYPTOパッケージについては、PL/SQL から利用するサンプルはたくさん見つかったのですが、SQL のみで実行するサンプルがなかなか見つかりませんでした。試しに、以下の SQL で実行してみました。

select
UTL_RAW.CAST_TO_VARCHAR2(
  UTL_ENCODE.BASE64_ENCODE(
    DBMS_CRYPTO.HASH(UTL_I18N.STRING_TO_RAW('mypassword', 'JA16SJIS'), DBMS_CRYPTO.HASH_SH1)
  )
)
from dual;

そうすると、以下のエラーが出てうまくいきません。

「ORA-06553: PLS-221: 'HASH_SH1'がプロシージャではないか、または未定義です」

それは確かにそうなんですが。。。いろいろ調べた結果、DBMS_CRYPTO.HASH_SH1の値は3であることが判明しましたので、

select
UTL_RAW.CAST_TO_VARCHAR2(
  UTL_ENCODE.BASE64_ENCODE(
    DBMS_CRYPTO.HASH(UTL_I18N.STRING_TO_RAW('mypassword', 'JA16SJIS'), 3)
  )
)
from dual;

これでうまくいきました。ちなみに、

HASH_MD4 ・・・ 1
HASH_MD5 ・・・ 2
HASH_SH1 ・・・ 3

のようです。

Oracle パスワードが期限切れで接続できない

半年ほど前に導入したシステムから、以下のエラーが発生しました。

ORA-28001:パスワードが期限切れです

調べてみると、なんと Oracle は 11g になってからデフォルトで 180日になっているじゃないですか!「ORA-28001」で検索すればいくらでも情報はあるのですが、「Oracle導入時の注意点」ではちっとも見かけなかった情報でした。。。こういった勝手な仕様変更に腹が立つのは私だけでしょうか?

以下の方法で復旧しました。

1. DBサーバ上で sqlplus sys/<管理者パスワード> as sysdba で sqlplus を起動
2. 以下のコマンドを実行して該当アカウントを復旧
  SQL> alter profile default limit password_life_time unlimited;
  SQL> alter user <ユーザID> identified by <パスワード>;
  SQL> alter user <ユーザID> account unlock;

ちなみにトラブルとなったのは JBoss サーバでしたが、この対処のみで自然と復旧することができました。また、トラブルとなったユーザ以外にも、有効期限が切れている(または切れそうな)ユーザを、以下の SQL で調査しました。

SQL> select USERNAME, ACCOUNT_STATUS, LOCK_DATE, EXPIRY_DATE, PROFILE from dba_users;

ここで、必要なアカウントについて、ACCOUNT_STATUS が OPEN 以外(EXPIRED や EXPIRED & LOCKED 等)だと、アカウントが無効(もしくは無効になりかけ)ですし、EXPIRY_DATE が設定されていたら、将来無効になってしまいます。同様に、以下の対処で正常な状態にすることができます。

  SQL> alter user <ユーザID> identified by <パスワード>;
  SQL> alter user <ユーザID> account unlock;

ちなみにこの対処だと、今後の運用ではパスワード無期限が前提になりますが、そもそもデータベースサーバはそれでまったく問題はないと思います。むしろ有効期限切れにする意味が分からない。。。と思うのは私だけ?

Smartyでサニタイジング

PHPのサイトでテンプレートエンジンとしてSmartyを利用している場合、クロスサイトスクリプティング対策としてのサニタイジングのために、HTMLコードのエスケープ処理を行います。エスケープ処理の方法としては、以下のサイトがよくまとまっていると思います。

http://k-holy.hatenablog.com/entry/php-advent-2012

私も試しに

$smarty->escape_html = true;

の設定をしてみたのですが、なぜかエスケープされる場合とされない場合があります。おかしいな~と思っていろいろ試していると、

{$this->name}<br/>

の箇所で

{$this->name} <br/>

のように、{$・・・}の後にスペースを1つ入れるとちゃんとエスケープするようになりました。いったいどんな仕様なのやら。。。


2013年2月23日土曜日

Format系オブジェクトのマルチスレッド問題

運用中のJavaのシステムが、ある日突然おかしな日付(1970年とか)を出力する、そんなトラブルに遭遇した場合は、DateFormat オブジェクトの使い方をチェックしたほうが良いかもしれません。


class DateUtil {
    static SimpleDateFormat myFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    public static String format(Date date) {
        return myFormat.format(date);
    }
}

うっかりこんなコードを書いてしまう人はかなり多いと思います。しかし、Format系のクラスはマルチスレッド対応していないため、Web系のユーザが多いシステムで利用された場合、ごくまれに誤動作を起こし、おかしな出力になったりします。しかもこの現象は、そこそこユーザが多いシステムでも年に数回だったりするので、やっかいです。この場合、Format系のクラスは毎回 new で生成してやる必要があります。


class DateUtil {
    public static String format(Date date) {
        SimpleDateFormat myFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        return myFormat.format(date);
    }
}

ある意味 Java の世界では有名な JDK の不具合(?)ですが、知らない人も結構多いですね。。。