Fork me on GitHub

2010/12/15


このエントリーをはてなブックマークに追加
記号プログラミング大好きっ子の皆さん、こんにちわ。
Advent Calendarで書いてもよかったかもしれませんが、どちらかと言うと逆かなーとか思ったのでこちらで。 aaencodeと言えば、はせがわさんが作ったjavascript向けの変態難読化スクリプトの事ですが、これの利用価値として以前から考えていたapacheモジュール化をやってみました。
サーバ上のjavascriptファイルを可視状態で編集してもクライアントからは難読化されて見えるという代物。実装としてはapacheのOutputフィルタモジュールとなります。
aaencodeは実装としては結構簡単な作りなのでソース全体を公開します。
/**
 * mod_aaencode -- apache filter module encoding to japanese style emoticons.
 *
 * AUTHOR:
 *   Yasuhiro Matsumoto <mattn.jp@gmail.com> a.k.a mattn
 *
 * ORIGINAL IDEA:
 *   Yosuke HASEGAWA, http://utf-8.jp/
 *
 * COMPILING:
 *
 *  for Windows:
 *    apxs2 -i -a -c -Wc,-O2 mod_aaencode.c \
 *      libapr-1.lib libaprutil-1.lib libhttpd.lib
 *
 *  for UNIX:
 *    apxs2 -i -a -c -Wc,-O2 mod_aaencode.c -lapr-1 -laprutil-1
 *
 * INSTALLATION:
 *   add following line into your '.htaccess'.
 *
 *   AddOutputFilter AAENCODE .js
 */
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "http_log.h"
#include "ap_config.h"

#define PUT(f, bb, s) \
  APR_BRIGADE_INSERT_TAIL(bb, \
                  apr_bucket_immortal_create(s, strlen(s), f->c->bucket_alloc))

#define CTOI(c) ( \
  (c >= '0' && c <= '9') ? (c - '0') : \
  (c >= 'a' && c <= 'f') ? (c - 'a' + 10) : \
  (c >= 'A' && c <= 'F') ? (c - 'A' + 10) : -1)

static char
utf8len_tab[256] = {
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
};

static char
utf8len_tab_zero[256] = {
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0,
};

static int
utf_ptr2len(unsigned char* p) {
  int    len;
  int    i;

  if (*p == 0)
    return 0;
  len = utf8len_tab[*p];
  for (i = 1; i < len; ++i)
    if ((p[i] & 0xc0) != 0x80)
      return 1;
  return len;
}

static int
utf_ptr2char(unsigned char* p) {
  int    len;

  if (p[0] < 0x80)  /* be quick for ASCII */
    return p[0];

  len = utf8len_tab_zero[p[0]];
  if (len > 1 && (p[1] & 0xc0) == 0x80) {
    if (len == 2)
      return ((p[0] & 0x1f) << 6) + (p[1] & 0x3f);
    if ((p[2] & 0xc0) == 0x80) {
      if (len == 3)
        return ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6)
          + (p[2] & 0x3f);
      if ((p[3] & 0xc0) == 0x80) {
        if (len == 4)
          return ((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12)
            + ((p[2] & 0x3f) << 6) + (p[3] & 0x3f);
        if ((p[4] & 0xc0) == 0x80) {
          if (len == 5)
            return ((p[0] & 0x03) << 24) + ((p[1] & 0x3f) << 18)
              + ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6)
              + (p[4] & 0x3f);
          if ((p[5] & 0xc0) == 0x80 && len == 6)
            return ((p[0] & 0x01) << 30) + ((p[1] & 0x3f) << 24)
              + ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12)
              + ((p[4] & 0x3f) << 6) + (p[5] & 0x3f);
        }
      }
    }
  }
  /* Illegal value, just return the first byte */
  return p[0];
}

static apr_status_t
aaencode_output_filter(ap_filter_t* f, apr_bucket_brigade* bb) {
  const char* aa[] = {
    "(c^_^o)", // (c^_^o)
    "(\xef\xbe\x9f\xce\x98\xef\xbe\x9f)", // (゚Θ゚)
    "((o^_^o) - (\xef\xbe\x9f\xce\x98\xef\xbe\x9f))", // ((o^_^o) - (゚Θ゚))
    "(o^_^o)", // (o^_^o)
    "(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)", // (゚ー゚)
    "((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xce\x98\xef\xbe\x9f))", // ((゚ー゚) + (゚Θ゚))
    "((o^_^o) +(o^_^o))", // ((o^_^o) +(o^_^o))
    "((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (o^_^o))", // ((゚ー゚) + (o^_^o))
    "((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f))", // ((゚ー゚) + (゚ー゚))
    "((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xce\x98\xef\xbe\x9f))", // ((゚ー゚) + (゚ー゚) + (゚Θ゚))
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89", // (゚Д゚) .゚ω゚ノ
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xce\x98\xef\xbe\x9f\xef\xbe\x89", // (゚Д゚) .゚Θ゚ノ
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['c']", // (゚Д゚) ['c']
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f\xef\xbe\x89", // (゚Д゚) .゚ー゚ノ
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xd0\x94\xef\xbe\x9f\xef\xbe\x89", // (゚Д゚) .゚Д゚ノ
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]", // (゚Д゚) [゚Θ゚]
  };
  const char* head =
    "\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89= /\xef\xbd\x80\xef\xbd\x8d\xc2\xb4\xef\xbc\x89\xef\xbe\x89 ~\xe2\x94\xbb\xe2\x94\x81\xe2\x94\xbb   //*\xc2\xb4\xe2\x88\x87\xef\xbd\x80*/ ['_']; o=(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)  =_=3; " // ゚ω゚ノ= /`m´)ノ ~┻━┻   //*´∇`*/ ['_']; o=(゚ー゚)  =_=3;
    "c=(\xef\xbe\x9f\xce\x98\xef\xbe\x9f) =(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)-(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f); (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) =(\xef\xbe\x9f\xce\x98\xef\xbe\x9f)= (o^_^o)/ (o^_^o);" // c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)={\xef\xbe\x9f\xce\x98\xef\xbe\x9f: '_' ,\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89 : ((\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f] " // (゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚]
    ",\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f\xef\xbe\x89 :(\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89+ '_')[o^_^o -(\xef\xbe\x9f\xce\x98\xef\xbe\x9f)] " // ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)]
    ",\xef\xbe\x9f\xd0\x94\xef\xbe\x9f\xef\xbe\x89:((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_')[\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f] }; (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) [\xef\xbe\x9f\xce\x98\xef\xbe\x9f] =((\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89==3) +'_') [c^_^o];" // ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['c'] = ((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)+'_') [ (\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)+(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)-(\xef\xbe\x9f\xce\x98\xef\xbe\x9f) ];" // (゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['o'] = ((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)+'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f];" // (゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];
    "(\xef\xbe\x9fo\xef\xbe\x9f)=(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['c']+(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['o']+(\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89 +'_')[\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+ ((\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89==3) +'_') [\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f] + " // (゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] +
    "((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) +'_') [(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)+(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)]+ ((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+" // ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+
    "((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) - (\xef\xbe\x9f\xce\x98\xef\xbe\x9f)]+(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['c']+" // ((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+
    "((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)+'_') [(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)+(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)]+ (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['o']+" // ((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+
    "((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f];(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['_'] =(o^_^o) [\xef\xbe\x9fo\xef\xbe\x9f] [\xef\xbe\x9fo\xef\xbe\x9f];" // ((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];
    "(\xef\xbe\x9f\xce\xb5\xef\xbe\x9f)=((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+ (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xd0\x94\xef\xbe\x9f\xef\xbe\x89+" // (゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+
    "((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)+'_') [(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)]+((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [o^_^o -\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+" // ((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+
    "((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+ (\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89 +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]; " // ((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚];
    "(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)+=(\xef\xbe\x9f\xce\x98\xef\xbe\x9f); (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)[\xef\xbe\x9f\xce\xb5\xef\xbe\x9f]='\\\\'; " // (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\';
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f).\xef\xbe\x9f\xce\x98\xef\xbe\x9f\xef\xbe\x89=(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f+ \xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)[o^_^o -(\xef\xbe\x9f\xce\x98\xef\xbe\x9f)];" // (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];
    "(o\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9fo)=(\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89 +'_')[c^_^o];" // (o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o]; TODO
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) [\xef\xbe\x9fo\xef\xbe\x9f]='\\\"';" // (゚Д゚) [゚o゚]='\"';
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['_'] ( (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['_'] (\xef\xbe\x9f\xce\xb5\xef\xbe\x9f+" // (゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+
    "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)[\xef\xbe\x9fo\xef\xbe\x9f]+ "; // (゚Д゚)[゚o゚]+

  apr_status_t err;
  apr_size_t buf_len = 0;
  unsigned char* ptr;
  unsigned char* buf = 0;
  unsigned char s[16];

  err = apr_brigade_pflatten(bb, (char**)&buf, &buf_len, f->r->pool);
  if (err) return err;
  apr_brigade_cleanup(bb);

  PUT(f, bb, head);

  ptr = buf;
  while(ptr - buf <= buf_len) {
    unsigned int i, l = utf_ptr2len(ptr);
    unsigned int c = utf_ptr2char(ptr);
    if (l == 0 || c == 0) break;

    PUT(f, bb, "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)[\xef\xbe\x9f\xce\xb5\xef\xbe\x9f]+"); // (゚Д゚)[゚ε゚]+
    if (c <= 127) {
      sprintf(s, "%o", c);
      for (i = 0; i < strlen(s); i++) {
        PUT(f, bb, aa[CTOI(s[i])]);
        PUT(f, bb, "+ ");
      }
    } else {
      PUT(f, bb, "(o\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9fo)+ "); // (o゚ー゚o)+
      sprintf(s, "%04x", c);
      for (i = 0; i < strlen(s); i++) {
        PUT(f, bb, aa[CTOI(s[i])]);
        PUT(f, bb, "+ ");
      }
    }
    ptr += l;
  }
  PUT(f, bb, "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)[\xef\xbe\x9fo\xef\xbe\x9f]) (\xef\xbe\x9f\xce\x98\xef\xbe\x9f)) ('_');"); // (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');
  APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(f->c->bucket_alloc));

  //ap_remove_output_filter(f);
  return ap_pass_brigade(f->next, bb);
}

static void
aaencode_insert_output_filter(request_rec* r) {
  ap_add_output_filter("AAENCODE", NULL, r, r->connection);
}

static void
aaencode_register_hooks(apr_pool_t *p) {
  ap_register_output_filter("AAENCODE", aaencode_output_filter, NULL, AP_FTYPE_CONTENT_SET);
}

module AP_MODULE_DECLARE_DATA aaencode_module = {
  STANDARD20_MODULE_STUFF,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  aaencode_register_hooks
};
一応リポジトリのリンクも貼っておきますね。
mattn/mod_aaencode - GitHub

apache filter module encoding to japanese style emoticons.

https://github.com/mattn/mod_aaencode
コンパイルは
apxs2 -i -a -c -Wc,-O2 mod_aaencode.c -lapr-1 -laprutil-1
Windowsなら
apxs2 -i -a -c -Wc,-O2 mod_aaencode.c libapr-1.lib libaprutil-1.lib libhttpd.lib
でインストールまでやってくれます。apacheを再起動すれば準備完了。
使い方は .htaccess に
AddOutputFilter AAENCODE .js
と書くだけ。これで例えば
<html>
  <head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
  <script type="text/javascript" src="hello.js"></script>
</head>
<body>
  はろーわーるど
</body>
</html>
こんなソースがあって、「ほほーん。jsのソースはhello.jsか」と解析する人がいたとします。で、ブラウザのURL欄に直接 hello.js を足して中身を閲覧しようとする訳です。

だがしかし!
mod_aaencode
えっ!?
となる想定。
見た方はビックリするか、はたまた和むか...

ちなみにjqueryを食わすと結果が11メガバイトになったり、30秒近くレスポンスが返ってこないのはもちろん仕様です

ただ最近、aadecodeなんで物を作った人がいて、こちらもそろそろ難読化レベルが下がってきているので、そろそろ新しい難読化技術を公開して欲しいですね!はせがわさん

Javascript ハンドブック (Next Generation Web Style) Javascript ハンドブック (Next Generation Web Style)
清野 克行
ソフトバンククリエイティブ / ¥ 2,499 (2010-12-17)
 
発送可能時間:在庫あり。

Posted at 03:10 in ソフトウェア::lang::c
Tagged as: aaencode, apache, c, mod_aaencode
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2009/09/24


このエントリーをはてなブックマークに追加
apacheでperlを扱うなら、CGI/FCGI/mod_perlといった選択肢があるのですが、mod_perliteという軽量なapacheモジュールも存在します。
sodabrew's mod_perlite at master - GitHub

A lightweight Apache module for Perl scripts

http://github.com/sodabrew/mod_perlite/
mod_perlは結構複雑ですが、mod_perliteは仕組みも簡素で分かりやすく速度パフォーマンスもそこそこあるという代物になっています。

mod_perliteについてはhidekさんの紹介記事を見ていただくと分かるかと思います。実はこのmod_perlite、絶賛の声はあれどPOSTメソッドが動かないという重大なバグを持ったまま今日に至ります。
先日からWindows向けにportingしている最中にその事実に気づき、「ええぃどうせならPOST出来る様にしてしまえ!」とpatchを書いたのが今日の昼。githubでpull requestしたのでauthorの方が今頃吟味検討してmergeするかどうかを判断しておられる頃かと思います。
変更差分を見られたい方はこの辺で...

何個か動作確認を行い、blosxomMTOS(Movable Type Open Source)、Catalyst(CGI)、MENTAが動作するのは確認しました。
mod_perlite_blosxom

mod_perlite_catalyst

mod_perlite_mtos

mod_perlite_menta
ただし完璧に動作するという訳でもなく、mod_perliteは内部でperlスクリプトをrun_fileするという簡素な仕様が故に、perl内でシグナルハンドラを書き換えられてしまうと、勝手に終了されてしまうという問題があります。デフォルトだと標準出力されるように$SIG{__DIE__}、$SIG{__WARN__}を書き換えてあるのですが、高性能なWAFはだいたいそのWAF専用のエラー画面を持っていて、内部でシグナルハンドラを上書きしている事があります。この場合、run_fileしてるだけなのでhttpサーバごとダウンするという、とてもおちゃめな動きになります。

とりあえずPOSTが動くようになってWindowsでも動かせる様になったので残る大きな問題は、この$SIG問題だと認識しています。
この辺はおそらくtieを使えばクリア出来るんじゃないかと思ってます。
Posted at 21:59 in ソフトウェア::lang::c
Tagged as: apache, C, perl
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2009/07/21


このエントリーをはてなブックマークに追加
jjencode素晴らしいですね。記号だけでjavascriptが実行出来てしまいます。
何かに使えないかなーと考えて、apacheのmod_ext_filterを使ってjavascriptの難読サーブをやってみようかと思います。
javascriptエンジンとして使うのは、v8。本当は全部Cで書けば速いのでしょうがメンドクサイのでやりません。
以下フィルタのソース
crypt-js.cc
#include <v8.h>
#include <string>
#include <iostream>

static std::string&
replace_string(std::string& str, const std::string from, const std::string dest) {
    std::string::size_type n, nb = 0;
    while((n = str.find(from, nb)) != std::string::npos) {
        str.replace(n, from.size(), dest);
        nb = n + dest.size();
    }
    return str;
}

v8::Handle<v8::Value> Print(const v8::Arguments& args) {
  bool first = true;
  for (int i = 0; i < args.Length(); i++) {
    v8::HandleScope handle_scope;
    if (first) {
      first = false;
    } else {
      printf(" ");
    }
    v8::String::Utf8Value str(args[i]);
    const char* cstr = *str ? *str : "";
    printf("%s", cstr);
  }
  printf("\n");
  return v8::Undefined();
}

int main(int argc, char* argv[]) {
  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
  v8::HandleScope handle_scope;
  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
  global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
  v8::Handle<v8::Context> context = v8::Context::New(NULL, global);
  v8::Context::Scope context_scope(context);

  std::string line, content;
  while(!std::cin.eof()) {
    std::getline(std::cin, line);
    content += line;
  }
  replace_string(content, "\\", "\\\\");
  replace_string(content, "'", "\\'");
  line = "var text = '";
  line += content;
  line += "';";
  line +=
    "var r=\"\";"
    "var n;"
    "var t;"
    "var b=[ \"___\", \"__$\", \"_$_\", \"_$$\", \"$__\", \"$_$\", \"$$_\", \"$$$\", \"$___\", \"$__$\", \"$_$_\", \"$_$$\", \"$$__\", \"$$_$\", \"$$$_\", \"$$$$\", ];"
    "for( var i = 0; i < text.length; i++ ){"
    "    n = text.charCodeAt( i );"
    "    if( n < 128 ){"
    "        r += \"\\\"\\\\\\\\\\\"+\" + n.toString( 8 ).replace( /[0-7]/g, function(c){ return \"$.\"+b[ c ]+\"+\" } );"
    "    }else{"
    "        r += \"\\\"\\\\\\\\\\\"+$._+\" + n.toString(16).replace( /[0-9a-f]/gi, function(c){ return \"$.\"+b[parseInt(c,16)]+\"+\"} );"
    "    }"
    "}"
    "print("
    "\"$=~[];$={___:++$,$$$$:(![]+\\\"\\\")[$],__$:++$,$_$_:(![]+\\\"\\\")[$],_$_:++$,$_$$:({}+\\\"\\\")[$],$$_$:($[$]+\\\"\\\")[$],_$$:++$,$$$_:(!\\\"\\\"+\\\"\\\")[$],$__:++$,$_$:++$,$$__:({}+\\\"\\\")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};\"+"
    "\"$.$_=\"+"
    "\"($.$_=$+\\\"\\\")[$.$_$]+\"+"
    "\"($._$=$.$_[$.__$])+\"+"
    "\"($.$$=($.$+\\\"\\\")[$.__$])+\"+"
    "\"((!$)+\\\"\\\")[$._$$]+\"+"
    "\"($.__=$.$_[$.$$_])+\"+"
    "\"($.$=(!\\\"\\\"+\\\"\\\")[$.__$])+\"+"
    "\"($._=(!\\\"\\\"+\\\"\\\")[$._$_])+\"+"
    "\"$.$_[$.$_$]+\"+"
    "\"$.__+\"+"
    "\"$._$+\"+"
    "\"$.$;\"+"
    "\"$.$$=\"+"
    "\"$.$+\"+"
    "\"(!\\\"\\\"+\\\"\\\")[$._$$]+\"+"
    "\"$.__+\"+"
    "\"$._+\"+"
    "\"$.$+\"+"
    "\"$.$$;\"+"
    "\"$.$=($.___)[$.$_][$.$_];\"+"
    "\"$.$($.$($.$$+\\\"\\\\\\\"\\\"+\" + r + \"\\\"\\\\\\\"\\\")())();\");";
  v8::Handle<v8::String> source = v8::String::New(line.c_str(), line.size());
  v8::TryCatch try_catch;
  v8::Handle<v8::Script> script = v8::Script::Compile(source, v8::String::New(""));
  v8::Handle<v8::Value> result = script->Run();
  return 0;
}

エスケープして変数textに入れて、残りはjjencodeそのままです。
これをhttpd.confで以下の様に設定します。
LoadModule ext_filter_module modules/mod_ext_filter.so
ExtFilterDefine crypt_js mode=output intype=application/x-javascript cmd="/path/to/crypt-js"
出来ました。簡単ですね。
これで以下のjavascriptをダウンロードしてみます。
window.alert('hasegawa!');
コマンドラインから...
curl http://localhost:8080/filter/foo.js
$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+"\\"+$.__$+$.$$_+$.$$$+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$.$_$+$.$$_+"\\"+$.__$+$.$__+$.$__+"\\"+$.__$+$.$_$+$.$$$+"\\"+$.__$+$.$$_+$.$$$+"\\"+$.$_$+$.$$_+"\\"+$.__$+$.$__+$.__$+"\\"+$.__$+$.$_$+$.$__+"\\"+$.__$+$.$__+$.$_$+"\\"+$.__$+$.$$_+$._$_+"\\"+$.__$+$.$$_+$.$__+"\\"+$.$_$+$.___+"\\"+$.$__+$.$$$+"\\"+$.__$+$.$_$+$.___+"\\"+$.__$+$.$__+$.__$+"\\"+$.__$+$.$$_+$._$$+"\\"+$.__$+$.$__+$.$_$+"\\"+$.__$+$.$__+$.$$$+"\\"+$.__$+$.$__+$.__$+"\\"+$.__$+$.$$_+$.$$$+"\\"+$.__$+$.$__+$.__$+"\\"+$.$__+$.__$+"\\"+$.$__+$.$$$+"\\"+$.$_$+$.__$+"\\"+$.$$$+$._$$+"\"")())();
おぉ!
HTMLから実行してみました。
hasegawa-crypt-js
おぉ!

これいいね!とか思ってjQueryでやってみたら、30秒以上は戻って来ませんでした... orz
Posted at 16:04 in ソフトウェア::lang::javascript
Tagged as: apache, javascript
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2009/02/09


このエントリーをはてなブックマークに追加
livedoor 製品で mod_access_token というのが出たみたいです。
livedoor ラボ「EDGE」 開発日誌 : 「mod_access_token」の配布開始と「EDGE src」公開のお知らせ - livedoor Blog(ブログ)

ウェブサイト上の画像やファイルに有効期限を指定して、ユーザーに一時的なダウンロードを許可する、ライブドアで独自開発したApacheモジュールです。このモジュールをApache Webサーバに組み込むことにより、画像やファイルをウェブ上で公開するときに有効期限をつけることができるようになり、Webアプリケーションと組み合わせる事で公開範囲の制御を行なう事が可能になります。

http://blog.livedoor.jp/edge_labs/archives/717201.html
modaccesstoken - Google Code

mod_access_token provides access token based secure downloading.

http://code.google.com/p/modaccesstoken/
ソースコード見たら依存が浅かったのでWindowsでビルドしてみた。
Makefile.w32
APACHE_ROOT=C:\Program Files\Apache Software Foundation\Apache2.2
CFLAGS=/I"$(APACHE_ROOT)\include" /DWIN32 /nologo
LDFLAGS=/LIBPATH:"$(APACHE_ROOT)\lib"
LIBS= libapr-1.lib libaprutil-1.lib libhttpd.lib

all : mod_access_token.so

mod_access_token.so : mod_access_token.obj
    link /nologo /DLL /OUT:$@ /EXPORT:access_token_module mod_access_token.obj $(LDFLAGS) $(LIBS)

mod_access_token.obj : mod_access_token.c
    cl -c $(CFLAGS) mod_access_token.c
なぜかmingw32では実行時にエラーが出たのであきらめました。VC6では可変長マクロが使えないので最終的にはVC8でしか試せませんでした。

ビルドしたモジュールを
C:\Program Files\Apache Software Foundation\Apache2.2\modules\
に置き、httpd.confへLoadModuleを追加。対象のフォルダに以下の様に設定(.htaccess)します。
.htaccess
AccessTokenCheck On
AccessTokenAccessKey foo
AccessTokenSecret bar
このAccessTokenAccessKey(foo)が公開鍵、AccessTokenSecret(bar)が秘密鍵になります。
認証はREADMEに書かれている通り
download.pl
use strict;
use URI;
use Digest::HMAC_SHA1;

my $access_key = 'foo';
my $secret = shift || die('specify secret key!');
my $exp = time + 300; # 5minutes
my $url = 'http://localhost:8080/access_token/example.jpg';
my $uri = URI->new( $url );
my $plain = sprintf '%s%s%s%s', 'GET', $uri->path, $exp, $access_key;
my $hmac = Digest::HMAC_SHA1->new( $secret );
$hmac->add( $plain );
my $sig = $hmac->b64digest;
$uri->query_form({
    Signature => $sig,
    AccessKey => $access_key,
    Expires => $exp,
});
printf "%s\n", $uri->as_string;
といった感じ。キーが間違ってるとDECLINED(Forbidden)になります。
内部はSHA1による認証処理になってます。

誰ですか!「WindowsなんてマイナーなOSのことは知りません」とか言ってるの!(謎)

追記
パッチを当てないと動かなかったのを忘れてました。
Index: mod_access_token.c
===================================================================
--- mod_access_token.c  (revision 3)
+++ mod_access_token.c  (working copy)
@@ -2,10 +2,12 @@
 #include "httpd.h"
 #include "http_config.h"
 #include "http_protocol.h"
+#include "http_request.h"
 #include "http_log.h"
 #include "ap_config.h"
 #include "apr_sha1.h"
 #include "apr_strings.h"
+#include "apr_base64.h"
 #include "apr_lib.h"
 
 #define ACCESS_KEY_NAME "AccessKey"
Posted at 17:21 in ソフトウェア::lang::c
Tagged as: apache
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip