それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

WEBユーザのログイン認証をssh経由でやる、割と強引な方法

認証面倒くさい。

LDAPで連携くんだり、PAMで認証したり、OAuthしたり、ユーザ認証をする方法は山ほどある。 でも、それぞれ一長一短があってそれらを解決するいい方法がほしいと思っていた。

WEBのユーザのログイン認証をSSHでやる

ひょんなことから、sshpass というコマンドを知ったので、これをつかって、WEBなどのユーザ認証をローカルのLinuxユーザーとパスワードで出来るんじゃないかと思ってやってみた。

仕組み

フォームから受け取ったユーザ名パスワードをつかってSSHで認証してOKならセッションを発行する

ssh のコマンドはパスワードを受け付けないし、expectなどは面倒なので sshpass コマンドを使うと解決する

サンプルコード

<?php
function alternative_pam_auth_by_shell_ssh( $user , $pass ){

  $allow_group='students'; //このグループに所属するユーザーだけに限定する
  if ( ! check_user_group($user, $allow_group ) ) {
    return false;
  }

  $sshpass = exec('/usr/bin/which sshpass');
  $user_esc = escapeshellarg($user);
  $pass_esc = escapeshellarg($pass);

  $cmd = "{$sshpass} -p ${pass_esc}  ssh -o 'StrictHostKeyChecking no' {$user_esc}@192.168.0.22 whoami 2>&1";
  $str = exec($cmd,$out,$ret);
  if ( $ret > 0  ){
    return false;
  }
  return strpos( $str, $user ) !== false;
}

root に総当りされる・・・

このままだとroot に総当りされるので、WEBからのssh経由でログインできるユーザのグループを限定する

<?php
function check_user_group( $user, $group ) {

  $user = escapeshellarg($user);
  $groups = exec('/usr/bin/which groups');
  $cmd = "{$groups} '${user}'";
  $ret = exec($cmd, $code );
  $ok = strpos($ret ,$group) !== false ;

  return $ok;
}

割りと解決する

ユーザのログインを別個に作るのは、面倒だし。登録画面も面倒だ、SSHSSHで管理したいと思うし。

かといって、次のアイデアには各種の懸念もある。

  • LDAPにユーザ管理を任せるの設定が煩雑だ
  • LDAPだととldif を覚えるのがメンテ上のハードルになり教えるのが面倒だ。
  • PAMだとwww-data に 読み取り権限を与える必要がある。
  • あらゆるプログラムが/etc/shadow を読み取るわけにも行かないし。
  • setuid したコマンドを別途用意するのも面倒だ。
  • OAuthにたよるとSSHログインと管理が別になる
  • SSHをOAuth対応させるとなるとAuthenticator必須になったりコレも面倒だ。
  • MySQLをPAM認証してMySQLに投げるとshell経由じゃないと怒られる

どの方法も一長一短があってむずかしい。

SSH に丸投げでどうだろう。

そこで、ユーザー認証してくれるプログラムで常時起動してるものに認証を投げたら楽じゃんと思って試してみた。

sshにお願いするのはパスワードのチェックだけで権限などは別にいらないしセッション管理もWEBは独立してるので楽だ。 こういう専用のライブラリがアレば良いのだけれど。。。

しかたないんので こういう sshヒューリスティックなハックに頼ることになった。

どうせどの方法もメリットデメリットがあるので、一番手軽な方法があっても良いんじゃないかと思ったり。

認証ハック関連の商品