日历

« 2008-08-21  
     12
3456789
10111213141516
17181920212223
24252627282930
31      

我的栏目

RSS订阅

黑夜给了我黑色的眼睛,我却用它来寻找光明

将SSH与PHP相连接 确保传输数据的安全

2008-01-16 17:50:45

SSH可以通过将联机的封包加密的技术进行资料的传递; 使用SSH可以把传输的所有数据进行加密,即使有人截获到数据也无法得到有用的信息……  SSH可以通过将联机的封包加密的技术进行资料的传递; 使用SSH可以把传输的所有数据进行加密,即使有人截获到数据也无法得到有用的信息。同时数据经过压缩,大大地加快了传输的速度。总之,通过SSH的使 用,可以确保资料传输比较安全并且传输效率较高。PHPChina 开源社区门户Sm/F!x.WA z
  不过,并非所有人知道PHP可以与SSH连接的特性以及与执行远程命令的能力,不过这方面却非常有用。由于我们可以在很多不同的方面利用PHP,因此 它有很多设置选项来控制其行为。一组庞大的可选参数能够保证您可以将 PHP用于许多不同的目的,但这同时也意味着这些参数和服务端配置的组合会带来一些安全问题。笔者一直在PHPCLI应用程序中使用SSH,笔者是从 cronjobs中使用它的,不过一开始并非十分简单,可以说颇费周折。关于安全使用Shell2函数的手册也不是十分实用,笔者进行了多次试验之后才有 了今天这篇小文章,愿您读了之后能为您配置PHP节省一点儿时间。
wj!\x{&E_+z u-e0   在这篇文章中,笔者需要假设:
P-j'`&l`B2|T$` h0   你正在运行的操作系统是Debian / Ubuntu。如果你运行的不是Debian / Ubuntu,你可能需要用你的Linux发行版本提供的数据包管理器来替换本文对应内容。PHPChina 开源社区门户Xhc5lrxFF
  你运行的是PHP5.如果你运行的不是PHP5,可用PHP4代替之。PHPChina 开源社区门户A5Us i9Yzo7n
  你对PHP和服务器管理有基本的了解。
}(mp ii$p l5O!^0   你已经安装了PHP。PHPChina 开源社区门户'r}bIH
  先决条件
)f7boFAR/g9T(d+M0_0   安装程序包PHPChina 开源社区门户k R)F6pp4_;C
  首先,让我们安装下面的程序包:
5d'_l;APp1^0   sudo aptitude updatePHPChina 开源社区门户`8m L$L}
  sudo aptitude install php5-dev php5-cli php-pear buid-essential \PHPChina 开源社区门户JW4BTb
  openssl-dev zlib1g-devPHPChina 开源社区门户?o$M/o WJTd7e
  安装完成进入下一步。PHPChina 开源社区门户I*BeInm z
  编译libssh2PHPChina 开源社区门户^D_gd1HT\
  在从sourceforge网站下载了Libssh2之后,我们需要编译它,不过不要担心,你只需要按照如下的方法操作:
3NtOx&hIe5a/k0   cd /usr/srcPHPChina 开源社区门户0CL5ami| U UK5K
  wget surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gzPHPChina 开源社区门户2t&}"S$p:]`;r4\y
  tar -zxvf libssh2-0.14.tar.gzPHPChina 开源社区门户8J;N%RL uCl5i$|
  cd libssh2-0.14/
{ vM:v4NX0   ./configurePHPChina 开源社区门户\ fB!D5{"C
  make all installPHPChina 开源社区门户5Y?,jm^
  如果你想检查是否有了一个新版本,可以查看SF.NET.不过,0.14这个版本就足够了。PHPChina 开源社区门户b.Y2H3wwGi]
  安装
IIZ2q R&{0   安装ssh2.so
zi#r,y4R0   下一步,我们需要将libssh和 PHPr链接起来。有一个PECL模块可以完成这个功能。我们可以使用PEAR安装它。PHPChina 开源社区门户]w;M.GJ m
  pear install -f ssh2
"v"ZYI1?!|*O z0   -f参数确保SSH2被安装,即使并没有一个稳定的选择对象。你还可以使用如下的包名称:ssh2-beta来强行运行。PHPChina 开源社区门户7rP9B;ENys'zT
  现在你需要确保我们这个新的SSH2.SO模块被PHP加载。编辑你的php.ini文件(对于CLI实用程序:/etc/php5/cli/php.ini,对于Apache实用程序:/etc/php5/apache2/php.ini)
#Mi!DZ5@(v2[.D0   extension=ssh2.so
`K:Y4`6~B2a0   这应该放在“Dynamic Extensions”的下面,大约在第515行左右。PHPChina 开源社区门户EC'R iC,G
  PHP支持SSH编写代码PHPChina 开源社区门户 [P-u-C]a8K X
  你刚刚在PHP中启用了SSH2。那么现在应该如何利用它呢?有两个选择。SSH支持:PHPChina 开源社区门户)nuR/k#V+P8eG
  1.执行方法:
.C1CL9d&VY6~:ls3v?0   这告诉你的服务器的操作系统来执行什么东西,并且通过管道传回到你的脚本。PHPChina 开源社区门户&\ G&uX |s SI
  2.外壳方法:PHPChina 开源社区门户_}:U.fGM
  这种方法在操作系统中打开一个实际的外壳,这正像通过终端应用程序登录时所操作的那样。有一些路由器并没有一个完全的POSIX一致性实施过程,而是在你登录时立即运行其自身的应用程序。这时你就需要这种方法。PHPChina 开源社区门户 c,HL:|e)J.q}QqYy
  下面我们分别详述之:PHPChina 开源社区门户d(wnN:e'Si/p
  第一种方法:执行
rcoa&Pa*z0   你最好为下面的代码创建函数或者是一个类,不过本文仅仅起到一个为您提供基本观念的作用,所以说你可以如此开始:

CODE:

  if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist")
!f)J;_!mGmTI$@0
f5\"LBl'{{:{!G0 PHPChina 开源社区门户Y#P)jB_
PHPChina 开源社区门户S,G%ix7} Y"U3E
  // log in at server1.example.com on port 22
3fEf~TL7Xj0 PHPChina 开源社区门户E2R ^-]j/T!kF

Vn6T;` x!}J0
f!@ui Db o0e3^0   if(!($con = ssh2_connect("server1.example.com", 22))){PHPChina 开源社区门户 m/QIY!zZ%rL
PHPChina 开源社区门户+q6U&v;] a/d ^+s
PHPChina 开源社区门户0s^N?1p'l6I
PHPChina 开源社区门户"Nn3yoe"@
  echo "fail: unable to establish connection\n";PHPChina 开源社区门户^T$Z/@u8Ym,N

om `#J)p9h~A_0 PHPChina 开源社区门户 g wr)Oe.R-Ac}
PHPChina 开源社区门户,Y|\lg;x3c"V:Eh
  } else {
9VAos7be.a W2}0
?UM sC\)cBD0
]!H2[Rx7z{A0 PHPChina 开源社区门户 dNpF+JB p#~
  // try to authenticate with username root, password secretpasswordPHPChina 开源社区门户8kkDA2`MC

pV7[8p)N+Z0 PHPChina 开源社区门户;v!|#O)RG8c*iRA3I
PHPChina 开源社区门户jm#P0Y`Hri-_
  if(!ssh2_auth_password($con, "root", "secretpassword")) {PHPChina 开源社区门户 D6@z0}+} KAh O:q
PHPChina 开源社区门户*S,tJ%B~M8s
PHPChina 开源社区门户cm\6XT.O g0z4w

gov$h|f*~;m7l0   echo "fail: unable to authenticate\n";
+cz;Qn2?;|.WN v0
a}&j8m+U"v+i0 PHPChina 开源社区门户 W)p W ~S W7I0F

*J8fz/w6~N~Ka0   } else {
g!j5l8s|l)p0 PHPChina 开源社区门户4I'L hQ7yfW
PHPChina 开源社区门户3iN;Q!d._
PHPChina 开源社区门户1P.H@,c2b
  // allright, we're in!PHPChina 开源社区门户*qO/NO%yy+lM

3^F3R~^uL q@0
j%rEm&Z0
&@v7E{#z!W0   echo "okay: logged in...\n";
.FnbW s0
nfy _"U h#l_0 PHPChina 开源社区门户"lO!u \){8z
PHPChina 开源社区门户)oc|sHf
  // execute a command
W ]5a:dpy wG`0 PHPChina 开源社区门户(~X7W X_ o/Q
PHPChina 开源社区门户 EO _'P1},p.zl&P-cn
PHPChina 开源社区门户u)X5MBM
  if(!($stream = ssh2_exec($con, "ls -al" )) ){PHPChina 开源社区门户,C+y4hIF/w5D

QYC _w0
HCCm:l:K0 PHPChina 开源社区门户3C-i7JJ1oi
  echo "fail: unable to execute command\n";
%B E4K}xa0
#@(e GS^#v0 PHPChina 开源社区门户3["Wg\L
PHPChina 开源社区门户|~P:yGs
  } else{
2O }#{&tdL0 PHPChina 开源社区门户5QZtNb3e
PHPChina 开源社区门户8|jw'b hg

0mt Nyp'O0   // collect returning data from command
x` s3C3o%iA0 PHPChina 开源社区门户r0mzi~B
PHPChina 开源社区门户(Y;nw Ie;^_3O
PHPChina 开源社区门户n/K(|wn&Np
  stream_set_blocking( $stream, true );
o:i$CR#X&HF0 PHPChina 开源社区门户] tUa%m&k0h"R;i7R
PHPChina 开源社区门户PCwe4q._V
PHPChina 开源社区门户[1},x'];nc
  $data = "";
ZqC5my(FB0q0
@'L}+z"hh2i }s zV0
x#Y0GrI&d7Cq0
+qLsCN {*z0   while( $buf = fread($stream,4096) ){
Mma)| T _u$E9ni5j?0 PHPChina 开源社区门户MGxwG C t

9| rG[h2d]%d:n0 PHPChina 开源社区门户2j6nS1L"f-PUw-cu3^
  $data .= $buf;
iOB9`r|4|:[0 PHPChina 开源社区门户.BxPVK-S+Qk
PHPChina 开源社区门户!I5f3PF\$TR}
PHPChina 开源社区门户F_1UuS0E%F
  }PHPChina 开源社区门户 C6R#p d&]4A$b

&w7~:paB/vp$W*b0
F9o8j a?!QM0
aU)F%I(D&nB}0   fclose($stream);PHPChina 开源社区门户5P*nj[[RLeX

^#P$T0e|qm4w*r0
fm\7E)n0 PHPChina 开源社区门户+M TK;B Ar
  }PHPChina 开源社区门户4D_+z*G,`

|9z x2l!xn5l0
H qT uk3}'F^H0
oIPA%@4T k0   }
  第二种方法:外壳
6{9cJtv2d0   同样道理,你也可以为如下的代码编写函数或者一个类。不过,本文仅仅提供基本观念:

CODE:

  if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist")
2ON+]"y[0 PHPChina 开源社区门户 o6p @?SzYO4r#d
PHPChina 开源社区门户+uD$_(J MU

*iz*] ZU%^1u0   // log in at server1.example.com on port 22PHPChina 开源社区门户sT_ @n

#m8sY(d Z+{&|0
yP#N&kW|/u0
TEV+i4XY:n0   if(!($con = ssh2_connect("server1.example.com", 22))){
'd,hU:~n6q lIU0 PHPChina 开源社区门户f;gx5X)|2Ip@C |z

&T9Fk+S6}/VE%U0 PHPChina 开源社区门户`m$C-m\;A*X8N
  echo "fail: unable to establish connection\n";PHPChina 开源社区门户 l9]:a:h`.E6a

K TBE \L]9eN!\I0 PHPChina 开源社区门户'~9FD'g/S Y3t4UO'f

4Gn~,Lw/{R_"L0   } else {PHPChina 开源社区门户]9Cf)v5F&S;t
PHPChina 开源社区门户:A9kH)U9^X

K!Z6x/R$x.E"o Cx0
d2}*Z:i0F n/Z[fW-E+k0   // try to authenticate with username root, password secretpasswordPHPChina 开源社区门户e$\i4y {/HI5?

~(?b4J2\ t c0 PHPChina 开源社区门户bWk'x&X q+g N0df
PHPChina 开源社区门户iX-| Y\w9A X
  if(!ssh2_auth_password($con, "root", "secretpassword")) {PHPChina 开源社区门户|.G2GP bl\f
PHPChina 开源社区门户S kJE&a4JP6Sg
PHPChina 开源社区门户 _;z tw8P D;i

.q,N$Z/K2j0   echo "fail: unable to authenticate\n";PHPChina 开源社区门户T{3dj2Sk5J+g
PHPChina 开源社区门户o:@n[!B{'i)H QM
PHPChina 开源社区门户z:L&KD9{[)hU
PHPChina 开源社区门户j |9F e)eD]
  } else {PHPChina 开源社区门户\ ](B}f {Y,V

`VxZ\:M"r6o.nq0
fL r Du#Y%[7J I0
/E)zm)ZiQY L|0   // allright, we're in!
iU2v d5|p8fs-x0 PHPChina 开源社区门户$z\b*E5{pI,c\x

cN7]F"V;^0
w8\ P%`$]u"a0   echo "okay: logged in...\n";PHPChina 开源社区门户d|Vo lc&t-Z*z

CT0xJ*e7oB+u0 PHPChina 开源社区门户bsxSI4R
PHPChina 开源社区门户0tk`%g z?9gL?q
  // create a shell
.z\#bpk J^{ y;u0 PHPChina 开源社区门户8I"P)hoy1z)l a_5~
PHPChina 开源社区门户m p#] ^$U2UOPy

XV'n6S|{0   if(!($shell = ssh2_shell($con, 'vt102', null, 80, 40, SSH2_TERM_UNIT_CHARS))){
'e RuY9O {x0
1k"M"o!LL:W3l!V*]-O0
j*gY:m}H w0 PHPChina 开源社区门户tq+|i4EQ#?
  echo "fail: unable to establish shell\n";
/KG+u,UEt?5HT m0 PHPChina 开源社区门户9K~N|&@

2znU7[ew"T_`0 PHPChina 开源社区门户`!a qgX'M t;S+@
  } else{PHPChina 开源社区门户:B4S4@9Z#\$On*]

7V$Py)LX N0
3]-n$A4La0 PHPChina 开源社区门户1^ y rzn+A,S1I
  stream_set_blocking( $shell, true );PHPChina 开源社区门户*CBf-ebJ
PHPChina 开源社区门户"QgvKQRtPOWrIC

L-l0z#VXt\0
mS1WCB2~k?0   // send a command
n|KD.sX*A0 PHPChina 开源社区门户/|"Y ez"|$h

-{)_U)n;xG ~X.L0 PHPChina 开源社区门户M!J0d$uZP
  fwrite($shell,"ls -al\n");
TY-R-Shm&p0 PHPChina 开源社区门户s,?-JX(`eeD#D

Li0`x_g yXrW-|0 PHPChina 开源社区门户8I&Po1^]&QxO&n
  sleep(1);
w@vHo%o-MU0
3yNX4W([0
8M$k){JjI0
6Hg4c:| \#QA)p0   // & collect returning data
*G@A*f7i)sR&v0 PHPChina 开源社区门户c#d0X pJ#n

%r6?I1O5C[2P1K0
f GV9v1aXxC+sd0   $data = "";
~juz)q3I0
W {1i_%CvM0
#~.\sC'{P4K nN'l0 PHPChina 开源社区门户 { p"P#Xg
  while( $buf = fread($shell,,4096) ){PHPChina 开源社区门户jD0cz2crzA ~,N|
PHPChina 开源社区门户y(c.G+[7hb
PHPChina 开源社区门户0Cx^'KO/BR5p
PHPChina 开源社区门户lo8?HT Q
  $data .= $buf;PHPChina 开源社区门户|3J7e*qG
PHPChina 开源社区门户Fiq0~`

c}:{`s0 PHPChina 开源社区门户vb)LBs$D
  }
M QP&]X0t0 PHPChina 开源社区门户:WmI x}oqW
PHPChina 开源社区门户5J~b*Sh*_%p*Q
PHPChina 开源社区门户E`"v+v HnF,T
  fclose($shell);PHPChina 开源社区门户&L L^!K-Nl2vQ
PHPChina 开源社区门户?#O!lAFT
PHPChina 开源社区门户f U }Lgi(nW

-EM6`"p1t2a%jg0   }
~F7p;g s5h#q#?"Q0
i In(GZ&N0
| Mm.^FSW q+|0 PHPChina 开源社区门户.}X!`\8h5V'w
  }PHPChina 开源社区门户)]W6_W4z,?

.d4_.Z-akQ,_T8yAu0
a5_?@0m }#X.|Z*x.x0
4_Q4hl4N8Gl0   }
  小提示:
$fJq[7t"S?7Q0   有时服务器忙碌,或者一个连接出错,缓冲区没有数据,PHP脚本就会停止从一个命令输出(即使命令并没有完成!)中收集数据。你可以为此进行如下的操作:
N!p-n!S"pOy8y0   ssh2_exec($con, 'ls -al; echo "__COMMAND_FINISHED__"' );
0QE%b,e6i{0   现在,在你不断地检查缓冲区的循环中,只需要看一下COMMAND_FINISHED。因为你就可以知道你拥有了所有的数据。为了避免无限循环(死循环),可以用一个10秒的超时限制:

CODE:

  $time_start = time();PHPChina 开源社区门户i SZ0A`&N{:P

8UWp4Z_0ot0
3H;q6`5f&s-@I&L0
j'z s/Y*]0   $data = "";
k#}3~gB B4G0 PHPChina 开源社区门户A{ Zv2lz#_
PHPChina 开源社区门户t b d{.D$f

V]5?H~ N \0   while( true ){
0Fh?:f,GI ]a.D$TU$K0
m A P/~#b0 PHPChina 开源社区门户 R+UR~a^4}$CT
PHPChina 开源社区门户x[8]X9e1z k/v.m
  $data .= fread($stream, 4096);
%Mc$u jm6y{O ye:Pf%z0 PHPChina 开源社区门户 N&LS+IEJ

"G4p\3|mn9r \P-ym0 PHPChina 开源社区门户KQ}l`9y,a_Dt
  if(strpos($data,"__COMMAND_FINISHED__") !== false){PHPChina 开源社区门户u$I8K{ Qy

I c0h4w0A@w0Z/a0 PHPChina 开源社区门户'I lkw|}
PHPChina 开源社区门户-s&rMh1v#s6_3qn}
  echo "okay: command finished\n";PHPChina 开源社区门户5BZ^ ?2`,~E+x%a u
PHPChina 开源社区门户G&o.a3[[ Jy
PHPChina 开源社区门户Id ],kmty,\

!VC:Y8o[v}0   break;PHPChina 开源社区门户:z&f.^7aDe&|T,Z g.D
PHPChina 开源社区门户t |oso7vpcp

$P2s%A)@@0 PHPChina 开源社区门户!TFQ1W5t/|(u&xT \2K
  }
-P |zD ? A.|0
tz A kEI0
:~yMz{t0 PHPChina 开源社区门户)_I ~j3W2{
  if( (time()-$time_start) > 10 ){PHPChina 开源社区门户'v4TTa#{ s

OyJ,gJaG0
:H9^7sN9n0
w*aCig6y0   echo "fail: timeout of 10 seconds has been reached\n";PHPChina 开源社区门户"O6G9p)w @+zQ P
PHPChina 开源社区门户4H;?c&o!~

0QL&hKO6y7fbfN0 PHPChina 开源社区门户@I%n,TEa
  break;
$w:k:fF@^+^7s0
$l{LgPE:h[-i_0
g+KD v7}G1t#RZ Q\0
n Ad-T^9dml0   }PHPChina 开源社区门户+w&` ^ O2xc AE
PHPChina 开源社区门户v%[P"U2^7J3_
PHPChina 开源社区门户-VOb \0X5d/]E
PHPChina 开源社区门户8_C"EKUgzP
  }
  在上面的例子中,你最好将stream_set_blocking设为false。PHPChina 开源社区门户,H?+hM!o,KL
  通过SSH发送文件
iPT3eE0   ssh2_scp_send($con, "/tmp/source.dat", "/tmp/dest.dat", 0644);PHPChina 开源社区门户L ug\w rq#_#}z
  如果不能正常工作PHPChina 开源社区门户%\ el(C~5a4Q
  请检查如下的几个方面:PHPChina 开源社区门户zLc[)G&c hWI
  依照本文检查你操作的每一步PHPChina 开源社区门户0u+kH,Q4c7r
  在服务器端,在sshd_config 中必须启用“PasswordAuthentication yes”。在大多数服务器上默认值是yes,不过有些情况下,你可能需要将下面的一行加入到文件中,即亲自动手打开这个功能:PHPChina 开源社区门户+F-OD|!lp
  /etc/ssh/sshd_config:PHPChina 开源社区门户wH*~jOe
  # Change to yes to enable tunnelled clear text passwordsPHPChina 开源社区门户e;s-?6Q&vCe
  PasswordAuthentication yesPHPChina 开源社区门户6z`M!X3X{
  如果作了改变,就需要重新启动SSH:PHPChina 开源社区门户#qt!x${5gi,N
  /etc/init.d/ssh restart

TAG: php ssh 安全

luzhou(浅玉)的空间 luzhou 发布于2008-01-16 18:33:18
鼓励~~
Fa,w`_[8g3hPHPChina 开源社区门户
Open Toolbar