公司的代理伺服器用的是squid,基於IP地址和MAC地址進行許可權驗證允許部分用戶訪問Internet。無奈列位高手們早已通曉盜用IP、MAC的方法來繞過squid的限制。近來考慮改為帳號認證。
由於同時在維護一個郵件伺服器(qmail + vpopmail + mysql),郵件帳號用mysql管理,內網用戶人手一郵箱。為了便於用戶記憶,想直接使用郵件帳號和密碼作為squid的帳號密碼。
程序嘛,比較靠譜的是mysql_auth,無奈對c一竅不通,只能借鑒一下它的思路......乾脆自己寫一個吧。
其他已知資料:
《Squid中文權威指南》,第12章有一個perl的例子以及以下文字:
在squid和基本驗證器之間的介面非常簡單。squid發送用戶名和密碼到驗證器進程,他們以空格分開並以新行結束。驗證器在其他stdin里讀取用戶名和密碼。在檢查信用項后,驗證器將OK或ERR寫入stdout。
任何「不安全的URL」字元會參照RFC1738規則進行編碼。這樣,名字「jack+jill」變成了"jack%2bjill"。squid接受包含空格的用戶名和密碼。例如「a password」變成了「a%20password」。在解碼用戶名和密碼后,驗證器程序能處理空格和其他的特殊字元。
要點總結:從stdin讀取用戶名和密碼,用戶名和密碼以空格分隔,可能涉及解碼。vpopmail里用戶帳號和密碼分別是pw_name和pw_passwd列,建一個表squid,只有一列pw_name,把有權用戶的用戶名添加到表squid里,用pw_name列關聯兩個表查詢獲得pw_passwd,和用戶的輸入做比較,一致即驗證成功。
PHP代碼如下:
#!/usr/bin/php
<?php
ini_set("display_errors", false);
function valid($u, $p, $sql_link) {
$result = false;
$res = mysql_query("select pw_passwd from squid a, vpopmail b where a.pw_name='$u' and a.pw_name=b.pw_name", $sql_link);
$rows = mysql_num_rows($res);
if (1 == $rows) {
$data = mysql_fetch_object($res);
$passwd = $data->pw_passwd;
if ($passwd == crypt($p, $passwd)) {
$result = true;
}
}
return $result;
}
while (!feof(STDIN)) {
$sql_link = mysql_connect("x.x.x.x", "xxx", "yyy");
mysql_select_db("vpopmail", $sql_link);
$input = trim(fgets(STDIN));
$data = explode(' ', $input);
$username = rawurldecode($data[0]);
$password = rawurldecode($data[1]);
if (valid($username, $password, $sql_link)) {
fwrite(STDOUT, "OK\n");
} else {
fwrite(STDOUT, "ERR\n");
}
mysql_close($sql_link);
}
?>
上述代碼保存為/usr/lib/squid/my_auth.php,屬性如下:
-rwsr-x--- 1 root squid 843 09-25 15:12 /usr/lib/squid/my_auth.php
squid.conf的相關配置:
acl acl_valid_user proxy_auth REQUIRED
http_access allow acl_valid_user
http_access deny all
auth_param basic program /usr/lib/squid/my_auth.php
auth_param basic children 5
auth_param basic realm 網際網路訪問許可權驗證
auth_param basic credentialsttl 2 hours
auth_param basic casesensitive on
[ 本帖最後由 pangty 於 2008-10-1 20:13 編輯 ]
《解決方案》
樓主實驗過沒有,很感興趣
《解決方案》
是的,已經實際在用,效果不錯。
《解決方案》
這樣能保證帳號不被盜用么?
《解決方案》
樓主厲害
《解決方案》
昨天寫的《用php寫一個squid驗證輔助器(authentication helper)》實現了squid基於mysql的用戶帳號認證,今天再進一步修改一下程序,支持基於mysql的用戶+ip綁定認證功能。
使用/etc/squid/acl_valid_user.txt存放用戶的ip和帳號信息,ip和帳號以空格分隔,帳號與mysql數據表裡的用戶帳號是一致的,格式如下:
192.168.1.100 pangty
192.168.1.200 test
相應的修改squid.conf,使用ip_user_check來進行帳號與ip的關聯檢查
external_acl_type ip_user_check children=5 %SRC %LOGIN /usr/lib/squid/ip_user_check -f /etc/squid/acl_valid_user.txt
acl acl_ip_user_check external ip_user_check
acl acl_valid_user proxy_auth REQUIRED
http_access allow acl_valid_user acl_ip_user_check
http_access deny all
auth_param basic program /usr/lib/squid/my_auth.php
auth_param basic children 5
auth_param basic realm 網際網路訪問許可權驗證
auth_param basic credentialsttl 2 hours
auth_param basic casesensitive on
my_auth.php驗證輔助程序加入對acl_valid_user.txt的驗證,原來在mysql里創建的squid表作廢。
#!/usr/bin/php
<?php
ini_set("display_errors", false);
$datafile = "/etc/squid/acl_valid_user.txt";
function valid($u, $p, $sql_link) {
$result = false;
$res = mysql_query("select pw_passwd from vpopmail where pw_name='$u'", $sql_link);
$rows = mysql_num_rows($res);
if (1 == $rows) {
$data = mysql_fetch_object($res);
$passwd = $data->pw_passwd;
if ($passwd == crypt($p, $passwd)) {
$result = true;
}
}
return $result;
}
$data = file_get_contents($datafile);
$line = preg_split ("/\n/", $data);
foreach ($line as $l) {
$l = trim($l);
if (!empty($l)) {
list($k, $v) = preg_split("/ +|\s+/", $l);
$userarr[$v] = $k;
}
}
while (!feof(STDIN)) {
$sql_link = mysql_connect("x.x.x.x", "xxx", "yyy");
mysql_select_db("vpopmail", $sql_link);
$input = trim(fgets(STDIN));
list($u, $p) = split(" ", $input);
$username = rawurldecode($u);
$password = rawurldecode($p);
if (array_key_exists($username, $userarr) && valid($username, $password, $sql_link)) {
fwrite(STDOUT, "OK\n");
} else {
fwrite(STDOUT, "ERR\n");
}
mysql_close($sql_link);
}
?>
[火星人 ] 用php寫一個squid驗證輔助器(authentication helper)已經有486次圍觀