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

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

上一篇 / 下一篇  2008-01-16 17:50:45

查看( 908 ) / 评论( 1 )
SSH可以通过将联机的封包加密的技术进行资料的传递; 使用SSH可以把传输的所有数据进行加密,即使有人截获到数据也无法得到有用的信息……  SSH可以通过将联机的封包加密的技术进行资料的传递; 使用SSH可以把传输的所有数据进行加密,即使有人截获到数据也无法得到有用的信息。同时数据经过压缩,大大地加快了传输的速度。总之,通过SSH的使 用,可以确保资料传输比较安全并且传输效率较高。PHPChina 开源社区门户 j)v^+{C
  不过,并非所有人知道PHP可以与SSH连接的特性以及与执行远程命令的能力,不过这方面却非常有用。由于我们可以在很多不同的方面利用PHP,因此 它有很多设置选项来控制其行为。一组庞大的可选参数能够保证您可以将 PHP用于许多不同的目的,但这同时也意味着这些参数和服务端配置的组合会带来一些安全问题。笔者一直在PHPCLI应用程序中使用SSH,笔者是从 cronjobs中使用它的,不过一开始并非十分简单,可以说颇费周折。关于安全使用Shell2函数的手册也不是十分实用,笔者进行了多次试验之后才有 了今天这篇小文章,愿您读了之后能为您配置PHP节省一点儿时间。
E#J,q2bf0  在这篇文章中,笔者需要假设:
h]-H&hA6~0  你正在运行的操作系统是Debian / Ubuntu。如果你运行的不是Debian / Ubuntu,你可能需要用你的Linux发行版本提供的数据包管理器来替换本文对应内容。PHPChina 开源社区门户aGXOJ^6w
  你运行的是PHP5.如果你运行的不是PHP5,可用PHP4代替之。
%| Lj2M:N_3Sj0  你对PHP和服务器管理有基本的了解。
dl,U n4d0  你已经安装了PHP。PHPChina 开源社区门户3J2T$ZWT9|*FG
  先决条件PHPChina 开源社区门户+Jg$d Vy&J h V
  安装程序包PHPChina 开源社区门户*v5s,A1w6D0Q C$y
  首先,让我们安装下面的程序包:PHPChina 开源社区门户9K.{eh@H
  sudo aptitude update
6Ji"FW J F ~m0  sudo aptitude install php5-dev php5-cli php-pear buid-essential \
/q8d3d.\3N Wy0  openssl-dev zlib1g-dev
E0b$[)T"Czh A0  安装完成进入下一步。PHPChina 开源社区门户[0j8oWU2^
  编译libssh2
%R?#sJkQ b0  在从sourceforge网站下载了Libssh2之后,我们需要编译它,不过不要担心,你只需要按照如下的方法操作:
r*_.u c7]C0  cd /usr/srcPHPChina 开源社区门户 W/ne J|*cD7|8\r
  wgetsurfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gzPHPChina 开源社区门户F g7Irw
  tar -zxvf libssh2-0.14.tar.gzPHPChina 开源社区门户;K(cP R j
  cd libssh2-0.14/
F~&B(Jy E$viL$p"?0  ./configure
)n-[*ow8b0  make all install
r.v(xt0s!]"T8z+Y0  如果你想检查是否有了一个新版本,可以查看SF.NET.不过,0.14这个版本就足够了。
$xh*@t,{1Sm,]A1FG0  安装PHPChina 开源社区门户B [ Z_-P O
  安装ssh2.so
[+c*y:T kbSa |0  下一步,我们需要将libssh和 PHPr链接起来。有一个PECL模块可以完成这个功能。我们可以使用PEAR安装它。
|{|]Hs0  pear install -f ssh2PHPChina 开源社区门户 Z c6TB e
  -f参数确保SSH2被安装,即使并没有一个稳定的选择对象。你还可以使用如下的包名称:ssh2-beta来强行运行。PHPChina 开源社区门户sh*q:h9km4y,\
  现在你需要确保我们这个新的SSH2.SO模块被PHP加载。编辑你的php.ini文件(对于CLI实用程序:/etc/php5/cli/php.ini,对于Apache实用程序:/etc/php5/apache2/php.ini)
)Njh|)r5@X0  extension=ssh2.so
6L%p!|!`&U0  这应该放在“Dynamic Extensions”的下面,大约在第515行左右。
5K#A9j+f!r0  PHP支持SSH编写代码PHPChina 开源社区门户!`1X}[.R(]Bk'^%j ^
  你刚刚在PHP中启用了SSH2。那么现在应该如何利用它呢?有两个选择。SSH支持:
+W/z'u3ab([q2m0  1.执行方法:
'A'y J Lm2O0  这告诉你的服务器的操作系统来执行什么东西,并且通过管道传回到你的脚本。
8h0K4zh6ae0  2.外壳方法:PHPChina 开源社区门户7lR.N&mu HzHy
  这种方法在操作系统中打开一个实际的外壳,这正像通过终端应用程序登录时所操作的那样。有一些路由器并没有一个完全的POSIX一致性实施过程,而是在你登录时立即运行其自身的应用程序。这时你就需要这种方法。PHPChina 开源社区门户 SU~$n [2^&n
  下面我们分别详述之:
r*C!yt,ST]7}7`0  第一种方法:执行
J8FP.H`Q0L~C0  你最好为下面的代码创建函数或者是一个类,不过本文仅仅起到一个为您提供基本观念的作用,所以说你可以如此开始:

CODE:

q9T$`KP3mL3YB1?0  if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist")PHPChina 开源社区门户] [3QPT8|z@2Y!?
PHPChina 开源社区门户5T3eivN,V d

;k`"k&J4uO7|0Qp0PHPChina 开源社区门户u y%jO{h2ge]
  // log in at server1.example.com on port 22
.J*el!f~0PHPChina 开源社区门户)s KZGH)C N1b

}f0]S:AQT0
T q7A.O pN0  if(!($con = ssh2_connect("server1.example.com", 22))){PHPChina 开源社区门户 F!F8V/MF0|+XP

.r'A oQF)])t0PHPChina 开源社区门户M9S9h(V1cQ'Dy
PHPChina 开源社区门户&WN_v1w+J7q cSr
  echo "fail: unable to establish connection\n";
fP;h;[ POGS0
Kr GeLh_N0
]Nx!X0Q h0PHPChina 开源社区门户's1x HKp u
  } else {
)V)I$} n+p|/L4w0PHPChina 开源社区门户8Vs+} [ gjg z8EA

8Q0gj G]6L0PHPChina 开源社区门户#hK6Gls*XE
  // try to authenticate with username root, password secretpassword
Yj-?Bajd#]m-E0PHPChina 开源社区门户;FX,F4?(B,@ u9A W
PHPChina 开源社区门户 o:v'rz Y

@L)[^nN0  if(!ssh2_auth_password($con, "root", "secretpassword")) {
:`d-d'Be)YgF0PHPChina 开源社区门户2~T4S/P+][:QW
PHPChina 开源社区门户;?#YO"b&lh$Q6S2Z@

d `!JJ b/B0  echo "fail: unable to authenticate\n";
b2}esY(N m0
D3H J#j.@b n0PHPChina 开源社区门户g.Ak#d9y W6s
PHPChina 开源社区门户Qy t(|#U Z
  } else {
3]$V'O0j9O!go0
+aW/f;Z'}b$zF0
"}pBZ_*p!|0PHPChina 开源社区门户o3`"\!m6i2~&k(~
  // allright, we're in!
[8p$a#Z#s]5^| w D1E0PHPChina 开源社区门户(Kc5O)\4y7_j k {b
PHPChina 开源社区门户wOL:b)V/J7Y o Q,P
PHPChina 开源社区门户l!prkNU
  echo "okay: logged in...\n";
4K-?H%x}0PHPChina 开源社区门户8B9V.A l&@*_.gDG'TI
PHPChina 开源社区门户)c8pE tcqY\jF

$j#U(SP6B0  // execute a command
-PZ|)W9fl-L\0
&r:?/QCS#Ymx0PHPChina 开源社区门户#EDWc ~q t,w
PHPChina 开源社区门户zg;Y_Bf{
  if(!($stream = ssh2_exec($con, "ls -al" )) ){PHPChina 开源社区门户;Pe&]8n1h M)X

y7p+xJh-S O7Kk#A(z0PHPChina 开源社区门户%m'M9Jjey;N
PHPChina 开源社区门户R,I {T"m FS'pg
  echo "fail: unable to execute command\n";
:@*t6f9m0h/z/\(Y3k&a0PHPChina 开源社区门户j`sZgSW

0K%F:Ifo&m0
#^h8p$Q5e t t0  } else{
y5ER:K i(a)K0
z)CW M L @)F+@/df0
#f-h;cY C*io0
VF+af} T `i0  // collect returning data from command
/L$f ~V"pdD,u#M0PHPChina 开源社区门户!G9U5|7o7tN

5?m+@1jpP7T0
$o V.@6cb%^N:I~n0  stream_set_blocking( $stream, true );PHPChina 开源社区门户2V.g8]a:~0Co N,l
PHPChina 开源社区门户9tT5L,S'eoK

i ifL y4zxGr0
RpY!Q|SoG CR0  $data = "";PHPChina 开源社区门户.C#Ye$Y ^^ \z uNe

.uMaZ7eq A u@"].r5zJf0
w3w-^$|*Qyu'm2D0
U q0C*rn$Z0  while( $buf = fread($stream,4096) ){PHPChina 开源社区门户J_m&]I(|B
PHPChina 开源社区门户;~9` VO Gs+uW*h-qT+A
PHPChina 开源社区门户E!tL1~ `&w9f'Z)r
PHPChina 开源社区门户 ZN"ub-jG_@q
  $data .= $buf;PHPChina 开源社区门户A`$e&{Gm

? W,V0Ko)[!i0
*h R8OA+[B0
SN7R)k3_:dyEA s0  }
,C8S6Qv7O2i-vm-T6X)j0PHPChina 开源社区门户9s&\?x"pe D&A(}W

b&t5S6o8N|m0
t^;V9M;GeM0  fclose($stream);PHPChina 开源社区门户'i:V:z!E^8l
PHPChina 开源社区门户Ot(c$J]&U.K
PHPChina 开源社区门户 U&J&rI4e
PHPChina 开源社区门户]V,fT.m'wKVy2~)G
  }
w7p"k2Snm0PHPChina 开源社区门户(}3sG/hN8x
PHPChina 开源社区门户9L\_}4J L6fg~

Wev'cd0dZVN9f0  }
  第二种方法:外壳PHPChina 开源社区门户 ZK-QDP%O+F-|]
  同样道理,你也可以为如下的代码编写函数或者一个类。不过,本文仅仅提供基本观念:

CODE:PHPChina 开源社区门户'PX?n4z| i:}:ax$cl

  if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist")
1T@2]~H+p E g0
-@*A,jk^"B Wi"t0
+A,if4GTO f+G:m0PHPChina 开源社区门户D!M3AyE#{Y'b
  // log in at server1.example.com on port 22PHPChina 开源社区门户#b Q7\#N3H$`
PHPChina 开源社区门户:wV$QimGu
PHPChina 开源社区门户.m3b[*bB&^

&aAo;R1_H0P J,@XZ0  if(!($con = ssh2_connect("server1.example.com", 22))){PHPChina 开源社区门户O%c4n*k%o$m
PHPChina 开源社区门户G;WCV T)o

kBg%_m4[0
g$I%\!TH|0  echo "fail: unable to establish connection\n";PHPChina 开源社区门户 lL*_L-p8dA
PHPChina 开源社区门户| l#B9_G!l5x4j,q
PHPChina 开源社区门户P4sW]$Th-}/|
PHPChina 开源社区门户{In~y2Ri#B
  } else {PHPChina 开源社区门户{VB b8`| s

:rt8_I?0U!? v0
%I.s"g AAx0PHPChina 开源社区门户;]rX*WYh;Von[$J+X
  // try to authenticate with username root, password secretpassword
W@;b X)^Lk0
#tq'{'Xc6\j0
PrF0N,mt6y0
4lMS4v)d7aV0  if(!ssh2_auth_password($con, "root", "secretpassword")) {PHPChina 开源社区门户k-~9N"atP {

)fP:q,`O4nYi6\Ym0
#D9~DxbZ @#O8c$n0
-]}-M"t3lG0  echo "fail: unable to authenticate\n";PHPChina 开源社区门户"M%l ?-j;w

)lI j$E q?7|,C2u)\t0
j`5DF$^+}*I4~0PHPChina 开源社区门户 w4i+~ z^2cJP'^F%y
  } else {
)c"j}dx W-T0
x%I[Z z|0PHPChina 开源社区门户;i7F/I.BUVtRGf

$dbi!`BoW0  // allright, we're in!
?|(v(Hy|BAd0PHPChina 开源社区门户T.`I QZ[3v"p X
PHPChina 开源社区门户6E}%HEx t)~
PHPChina 开源社区门户*x~Hv[?
  echo "okay: logged in...\n";PHPChina 开源社区门户i%~.K.z$j2U
PHPChina 开源社区门户4i.P]%?5t&b

u'y*?Hj0PHPChina 开源社区门户l*^&r x*P-m'SK
  // create a shellPHPChina 开源社区门户?LpOw

6m*v3r$A#g0
HR"r1J#TZ0PHPChina 开源社区门户 W jy J-c}8s?
  if(!($shell = ssh2_shell($con, 'vt102', null, 80, 40, SSH2_TERM_UNIT_CHARS))){PHPChina 开源社区门户#J'@o$Cvt3n pBiN M
PHPChina 开源社区门户ygOyV\l0L_ u
PHPChina 开源社区门户4Rx.Y/H/L)~e
PHPChina 开源社区门户6_wgk(?'{ uR
  echo "fail: unable to establish shell\n";PHPChina 开源社区门户y)lb v.?"sA
PHPChina 开源社区门户iY8r1E6pB lQ2@

R7j.uV.};R6N0PHPChina 开源社区门户K-Vs2qL$c*RP
  } else{PHPChina 开源社区门户ADT;~N^7t

3LnJ{!?teLu0PHPChina 开源社区门户1_5L(p/mOq+J`
PHPChina 开源社区门户#i O HBk-mp8VfQ0x
  stream_set_blocking( $shell, true );
i1L6H5}2z"B-g0
CPG1y"H^[%m]g J0PHPChina 开源社区门户;C1s3`yZ
PHPChina 开源社区门户{l$C\0Q
  // send a commandPHPChina 开源社区门户 P-Sj&@lbg@)Y
PHPChina 开源社区门户{q+C7YY)x ^

G3KP;h ^W`9~0
d^5_"a\Kf5DG(Yv"K*E0  fwrite($shell,"ls -al\n");
S%Am)X&mk0
4u\w]1Y0PHPChina 开源社区门户Hsi3HX2z
PHPChina 开源社区门户-h'|/\^ O.]E7|3KF
  sleep(1);
']$p Wr1N5[\;d+e0PHPChina 开源社区门户f$h.V8a9B d oT
PHPChina 开源社区门户%n'B7O&Hug4P

5wI;H)b&O9Hl0  // & collect returning data
6eB6E t `O?0PHPChina 开源社区门户8[.})m _7A9t
PHPChina 开源社区门户CHQ\s.Q&aV@
PHPChina 开源社区门户d7}nX U a"v
  $data = "";PHPChina 开源社区门户ID$yr%pX)~Ff9r
PHPChina 开源社区门户2m6j7P@m7lMK3?"W(P B
PHPChina 开源社区门户%k O%ykA;w B P

s%Yc.nW6R1J0  while( $buf = fread($shell,,4096) ){
:[TGu3_w [7`0PHPChina 开源社区门户!q tU LZ~tM
PHPChina 开源社区门户1L+T%ClzM%L
PHPChina 开源社区门户;CyF9en,fZ)o+c;s
  $data .= $buf;PHPChina 开源社区门户3N0N"Y\&I'`
PHPChina 开源社区门户y Dw)OV5vqR
PHPChina 开源社区门户]e Lh+U3L
PHPChina 开源社区门户j u b-o"u`
  }PHPChina 开源社区门户.nu6Fk+e#Wm \8B!B

4zYb+K r)Q0PHPChina 开源社区门户7U$u Wm3n J9P

+h!z yiD r0  fclose($shell);
,s` JQ0R}5wi0PHPChina 开源社区门户E$U(h[2l y)[.l-g

y-v&w.mw@YX0
D6C!j~(z0  }
;F%S g_`0PHPChina 开源社区门户n!x(z X n.`\z
PHPChina 开源社区门户*KG,l8V&T%O9smz

4v}1r6o#_h*n0  }
?j3zeH;f0
`Q@ NS N5M/|q0PHPChina 开源社区门户9HH E"el Y
PHPChina 开源社区门户%CLMeLV/O
  }
  小提示:
]5n7x"XQ$`:m0  有时服务器忙碌,或者一个连接出错,缓冲区没有数据,PHP脚本就会停止从一个命令输出(即使命令并没有完成!)中收集数据。你可以为此进行如下的操作:
Jzfw P%H8E8Y0  ssh2_exec($con, 'ls -al; echo "__COMMAND_FINISHED__"' );PHPChina 开源社区门户K T3p;G9U"?1HY
  现在,在你不断地检查缓冲区的循环中,只需要看一下COMMAND_FINISHED。因为你就可以知道你拥有了所有的数据。为了避免无限循环(死循环),可以用一个10秒的超时限制:

CODE:

5\@!D1KA?+}i8?0  $time_start = time();PHPChina 开源社区门户no,QqMxK

9Dh3s~W*S!s0
1~Sqh:l GJ0
lGXJZ0  $data = "";
m~@)@6x U0
O eR,Hg f0
\u B2}J!j;O0
~3On+Yy3@ g.J1fO7@0  while( true ){
ex/p W0ghw0
oU7NCIQ+Q.rSj*MO0PHPChina 开源社区门户8jyg1K:h4\@9c
PHPChina 开源社区门户!w ~)s1\M%W"hI+lcJ
  $data .= fread($stream, 4096);PHPChina 开源社区门户.tpg(^:^g]^Os*D

.X%j+n4Jz0
k"H'`q0G7\:fY0
dS_zdv3MS,eZp0  if(strpos($data,"__COMMAND_FINISHED__") !== false){PHPChina 开源社区门户"hA"Q%FB ](?e
PHPChina 开源社区门户 \'z7j;F4Ly6n
PHPChina 开源社区门户%}+RH#e'q-C9Mb
PHPChina 开源社区门户+o%gmD`
  echo "okay: command finished\n";
].t&XA6R9fu6X0
uC9CD ~0
7]v%R;f!Q^2q-L0Q0PHPChina 开源社区门户E`;cr]
  break;
+lG'\5Y _K]0PHPChina 开源社区门户-I#v[$m/} {jH
PHPChina 开源社区门户WT%q4{H_^"{v|4T5h]

&~KvL-f0  }
T;`2F'@ ybvP0v0
2a\!^ Lf1`0PHPChina 开源社区门户mEDLQ6X^

Atf$fAz6JW@&s2H!_0  if( (time()-$time_start) > 10 ){
`&n2m(g:H&igK0
,Ir6_6_o-c zR.y3c0
]0e6dhUh|X M$N0PHPChina 开源社区门户0c4d[-s~x,z0sh
  echo "fail: timeout of 10 seconds has been reached\n";
$Em+yY-j;Z#]1k"Z0
;E6y:l!e_z)h0
4nTE0Dx\2k0PHPChina 开源社区门户S-C5Bu {:g!Hq"D
  break;PHPChina 开源社区门户'Wcq _ r?U2E

.}bhWT&n0
+zU2["Z!w,e&@#{$a!?0PHPChina 开源社区门户6uK$ny&_o#m#@
  }PHPChina 开源社区门户 X5v0J r FG Y

#r/]:j9@&t0PHPChina 开源社区门户 Q*ieKW5L&Ia3\-p
PHPChina 开源社区门户&MS"I"O9M/w \ X%OB
  }
  在上面的例子中,你最好将stream_set_blocking设为false。
-PF-U6K.W,{zY(N p!T0  通过SSH发送文件
ZN k5bU5^R0  ssh2_scp_send($con, "/tmp/source.dat", "/tmp/dest.dat", 0644);
.EY:CYh+v&v0  如果不能正常工作PHPChina 开源社区门户?gt eN0D
  请检查如下的几个方面:
)X.m6Akg(n0  依照本文检查你操作的每一步
"q"u,ToDG1R}0  在服务器端,在sshd_config 中必须启用“PasswordAuthentication yes”。在大多数服务器上默认值是yes,不过有些情况下,你可能需要将下面的一行加入到文件中,即亲自动手打开这个功能:PHPChina 开源社区门户.K4rw%[F Qjh$|
  /etc/ssh/sshd_config:PHPChina 开源社区门户~g`+G0T,Anz
  # Change to yes to enable tunnelled clear text passwordsPHPChina 开源社区门户Y!e P Zr5I
  PasswordAuthentication yes
1N1} ZaB'j[A#?$Z0  如果作了改变,就需要重新启动SSH:PHPChina 开源社区门户3TxM$Gb!M:O Ez#w6Oa
  /etc/init.d/ssh restart

TAG: php ssh 安全

luzhou(浅玉)的空间 luzhou 发布于2008-01-16 18:33:18
鼓励~~
:M
z{ H#TW&}www.phpchina.com

我来说两句

(可选)

数据统计

  • 访问量: 4405
  • 日志数: 34
  • 图片数: 1
  • 书签数: 1
  • 建立时间: 2007-11-21
  • 更新时间: 2008-04-11

RSS订阅

Open Toolbar