热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Sendmail的安全配置

安全与sendmail随着Internet的爆炸性增长,像sendmail这样接受用户所提供的任意输入并把它投递给本地用户、文件或shell的应用常常会为黑客们提供一条实施攻击的坦途。sendmail和DNS甚至IP,正在尝试把身份验证和加密作为内建的解决方案以解决一些基本的安全

安全与sendmail

随着Internet的爆炸性增长,像sendmail这样接受用户所提供的任意输入并把它投递给本地用户、文件或shell的应用常常会为黑客们提供一条实施攻击的坦途。sendmail和DNS甚至IP,正在尝试把身份验证和加密作为内建的解决方案以解决一些基本的安全性问题。

最近美国关于加密技术的出口法规开始松动,这使得sendmail在发布时可以内建对加密功能的挂接接口。版本8.11及其后继版本都支持用SSL(Secure Socket Layer,安全套接口协议层)进行SMTP身份验证和加密,SSL也称为TLS(Transport Layer Security,传输层加密)。sendmail在这里使用术语TLS,并且已经把它作为对SMTP协议的一种扩展?STARTTLS?实现了。TLS给它带来了6个用于鉴定文件和给文件上锁的新配置选项。对访问数据库进行匹配的新操作要求身份验证必须先取得成功。

在本节中,我们将描述sendmail的权限模型、所有权和隐私保护的演变。然后简要讨论SASL(Simple Authentication and Security Layer,简单身份验证和加密层协议)和它在sendmail中的使用。

随着时间的推移,sendmail已经逐渐加强了它的安全性,现在,在它相信一个文件(比如说.forward或aliases)之前,它对文件权限是非常挑剔的。虽然这种安全性的加强通常会受到欢迎,但有时也有必要放松强硬的新规则。为了达到这个目的,sendmail引入了DontBlameSendmail选项,这样命名是希望这个名字会提醒系统管理员,他们正在做被大家认为是不安全的事情。

这一选项有许多可能的值?最新统计有55种之多。默认值是safe。值的完整列表请参见sendmail软件发布里的doc/op/op.ps这个文件。还是继续把这个选项设置为safe吧。


所有权

在sendmail世界中有3个用户账号很重要:DefaultUser、TrustedUser和RunAsUser。

默认情况下,除非邮寄程序的标志位另行指定,否则所有sendmail的邮寄程序都作为DefaultUser运行。如果在/etc/passwd文件中存在用户mailnull、sendmail或者daemon,那它就是DefaultUser了。否则,它默认为UID 1和GID 1。我们推荐使用mailnull账号和一个mailnull组。把它添加到/etc/passwd中,用一个星号作为口令,没有有效的shell,没有主目录,默认属组为“nogroup”。您也要在/etc/group文件里加上mailnull。Mailnull账号不应该拥有任何文件。如果sendmail不是以root身份运行的,那么邮寄程序必须设置setuid位。

如果设置了RunAsUser,那么sendmail会忽略DefaultUser的值,而以RunAsUser的身份完成所有工作。如果您正在以setgid(到smmsp)方式运行sendmail,那么提交邮件的sendmail只是通过SMTP把消息传递给真正的sendmail。真正的sendmail没有设置它的setuid位,但它的启动脚本需以root身份运行。

sendmail的TrustedUser可以拥有映射和别名文件。TrustedUser可以启动守护进程或重建aliases文件。之所以存在这个功能多是为了支持sendmail的GUI界面,需要这样的界面来向有些用户提供受限的管理控制权。如果您设置了TrustedUser,那么就要保护好它所指向的账号,因为这个账号很容易被利用,得到root权限。TrustedUser不同于称为TRUSTED_USERS的sendmail类,后者决定谁可以重写消息的From行 。

sendmail打开到端口25的套接口连接之后,以RunAsUser作为UID来运行。编号小于1024的端口只能由超级用户打开,因此,sendmail最初必须作为root运行。不过,执行完这项操作之后,sendmail可以切换到另一个UID。如果sendmail被欺骗做一些不好的事,这种切换就降低了损害或访问的风险。不要在支持用户账号或者其他服务的机器上使用RunAsUser功能,它是只供防火墙或者堡垒主机使用的。

在默认情况下,sendmail不切换身份并继续作为root运行。如果您把RunAsUser改为不是root的其他身份,那么还必须修改其他几个地方。
RunAsUser必须拥有邮件队列,能够读取所有的映射和包含文件,能够运行程序等。估计要花几个小时才能找出所有必须修改的文件和目录的所有权关系。


权限

文件和目录权限对sendmail的安全性十分重要。请使用表18.14中列出的设置以确保安全。

表18.14 sendmail相关目录的属主和权限

路    径

属    主

模    式

内    容

/var/spool/clientmqueue

smmsp

770

初始提交的邮件队列a

/var/spool/mqueue

RunAsUser

700

邮件队列目录

/, /var, /var/spool

root

755

mqueue的路径

/etc/mail/*

TrustedUser

644

映射、配置文件、别名

/etc/mail

TrustedUser

755

映射文件的父目录

/etc

root

755

Mail目录的路径

a.8.12及以后版本。

sendmail不会读取权限过于宽松的文件(例如,任何组或任何人都可写的文件,或者位于任何组或任何人都可写的目录中的文件)。sendmail对所有权和权限很严格的部分原因,是有一些操作系统允许用户用chown将自己的文件转让出去(那样的操作系统大多都是从System V演变而来的)。

Linux系统默认都有一个健全版本的chown,它们不允许转让文件。不过,在代码中设置一个预编译指令#ifdef就可以让chown采用System V的语义(CAP_CHOWN)。您还要重新编译内核。但是这种做法并不好,不要迫使您原本合理的Linux的chown按照有缺陷的System V的方式来运行。
特别地,sendmail对任何别名(aliases)文件或者转发(forward)文件的完整路径非常挑剔。这么挑剔的话,有时会和站点管理Majordomo邮递列表别名的方式发生冲突。例如,如果Majordomo列表位于/usr/local,那么整个路径必须是可信的,路径的各个部分都没有组写权。这项限制让列表的所有者更难以管理别名文件。要看看在sendmail对于权限的考虑上,您做得如何,可以运行:

 define(‘LUSER_RELAY',  ‘error:No  such  user')
-bi标志初始化别名数据库,如果权限不对就向您发出警告。

如果到某个文件的目录路径是不安全的(权限过于宽松),sendmail将不再读取链接数大于1的.forward文件。这条规则在最近就让Evi碰上了,因为她的.forward文件在把她的邮件从她不会收到太多邮件的小站点转发过来时一声不响地就失败了,这个文件在一般情况下是到.forward.to.boulder或.forward.to.sandiego的一个硬链接。过了好几个月她才意识到并明白过来,“我从没收到过您的信”是她的错,并且再也不是一个说得过去的借口了。

可以用DontBlameSendmail选项关掉上面提到的许多限制文件访问的规则。但是不要那么做。


发到文件和程序的可靠邮件

我们建议您使用smrsh代替/bin/sh作为您的邮寄程序(mailer),并用mail.local代替/bin/mail作为本地邮寄程序。这两个程序都包含在sendmail的软件发布中。为了把它们合并到您的配置中,请把以下两行:

 FEATURE(‘smrsh',  ‘path-to-smrsh')
FEATURE(‘local_lmtp',  ‘path-to-mail.local')

添加到您的.mc文件中。如果省略了明确的路径,就认为命令位于/usr/libexec下。您可以使用sendmail的confEBINDIR选项把二进制程序的默认位置改为您需要的任何地方。Red Hat的默认安装根本就没有提供mail.local。SUSE把它放在/usr/lib/sendmail.d/bin下,而Debian和Ubuntu把它们藏在了/usr/lib/sm.bin里。

smrsh是一个受限的shell,它只执行一个目录中包含的程序(默认情况下是/usr/adm/sm.bin)。Red Hat和Fedora把smrsh这个二进制程序安装在/usr/sbin下,SUSE把它放在/usr/lib/sendmail.d/bin下,而Debian和Ubuntu把它放在/usr/lib/sm.bin里。smrsh忽略用户指定的路径,并试图在它自己已知是安全的目录中找到要求执行的任何命令。smrsh还禁止使用某些shell元字符,比如“<”,即输入重定向符。在sm.bin中允许用符号链接,所以您不需要给允许使用的程序做副本 。

下面是一些shell命令的例子,以及smrsh给它们可能的解释:

 vacation  eric                      #  执行 /usr/adm/sm.bin/vacation  eric
cat  /etc/passwd                   #  被拒绝,在sm.bin里没有cat命令
vacation  eric  <  /etc/passwd  #  被拒绝,不允许有<
在电子邮件被一个aliases或者.forward文件重定向到一个文件的时候,sendmail的SafeFileEnvironment选项控制着可以把文件写到什么地方。它会让sendmail执行一次chroot系统调用,让文件系统的根不再是/而是/safe,或者您在SafeFileEnvironment选项中指定的任何路径。例如,把邮件重定向到/etc/passwd文件的别名实际上是写入了/safe/etc/passwd。

SafeFileEnvironment选项也能通过只允许写入普通文件的做法,保护设备文件、目录和其他的特殊文件。除了提高安全性之外,这个选项还有助于缓解用户犯错所造成的影响。有些站点把这个选项设为/home,在禁止进入系统文件的时候,能够访问用户的主目录。

邮寄程序(mailer)也可以进入被chroot过的目录。目前必须在邮寄程序的定义中指定该选项,但它应该很快就能通过m4来配置了。


隐私选项

sendmail还具有隐私选项,可控制:

哪些外部人员可以由SMTP来测定您的站点;
您对SMTP连接的另一端主机有什么要求;
您的用户是否可以看到或者运行邮件队列。

表18.15列出了在撰写本书的时候隐私选项可能的值,关于当前的信息请参见软件发布中的doc/op/op.ps文件。

我们建议您保守一些,请把:

 define(‘confPRIVACY_OPTIONS', “goaway,  authwarnings,  restrictmailq,
restrictqrun")
用在.mc文件中。sendmail隐私选项所用的默认值是authwarnings,上面这一行将重置该值。请注意有两组引号,某些版本的m4需要用它们把隐私选项值列表中的逗号括起来。Red Hat和Fedora默认选authwarnings,而SUSE、Debian和Ubuntu默认选authwarnings,needmailhelo、novrfy、noexpn和noverb。

表18.15 PrivacyOption变量的值

含    义

Public

不作隐私/安全检查

Needmailhelo

要求有SMTP HELO(识别远程主机)

Noexpn

不允许SMTP EXPN命令

Novrfy

不允许SMTP VRFY命令

Needexpnhelo

不扩展没有HELO的地址(EXPN)

Needvrfyhelo

不验证没有HELO的地址(VRFY)

noverba

不允许EXPN使用详细(verbose)模式

Restrictmailq

只允许mqueue目录的属组看到队列

Restrictqrun

只允许mqueue目录的属主运行队列

Restrictexpand

-bv-v标志限制显示的信息b

noetrnc

不运行异步方式运行排队操作

Authwarnings

添加Authentication-Warning(身份验证警告)信头(这是默认值)

Noreceipts

关闭成功回执的DSN(delivery status notification,投递状态通知)

Nobodyreturn

不在DSN中返回消息主体

Goaway

禁止所有的SMTP状态查询(EXPN、VRFY等)

a.在发出EXPN命令的时候,详细模式会根据.forward文件,提供有关用户邮件行踪的更多信息。在任何向外界暴露的机器上,应使用noverb,当然noexpn更好。
b.除非由root或者TrustedUser执行。
c.ETRN是一条ESMTP命令,它是专为拨号主机的使用而设计的。它要求只对到该主机的消息运行排队操作。


运行chroot后的sendmail

如果您担心sendmail会访问您的文件系统,那么可以在由chroot建成的“监管环境(jail)”中启动它。在监管环境中构造一个最小的文件系统,包括/dev/null、/etc的要素(passwd、group、resolv.conf、sendmail.cf、所有映射文件、mail/*)、sendmail需要的共享库、sendmail二进制文件、邮件队列目录、以及所有日志文件。您可能不得不手忙脚乱半天才能彻底解决问题。使用chroot命令启动一个受监控的sendmail。例如:

 #  chroot  /jail  /usr/sbin/sendmail  -bd  -q30m


拒绝服务攻击

要防止拒绝服务攻击(denial of service,DoS)是很困难的,因为没有一种方法可以预先知道一则消息是一个攻击还是一份有效的电子邮件。攻击者可以尝试各种卑鄙的招数,包括用假连接淹没SMTP端口,用巨大的消息填满磁盘分区,阻塞向外的连接,以及邮件炸弹。sendmail有一些配置参数可以帮助减慢或限制一次拒绝服务攻击的冲击,但是这些参数也会妨碍合法的邮件传输。邮件过滤库(milter)可能会帮助系统管理员对抗一次长时间的拒绝服务攻击。

MaxDaemonChildren选项可以限制sendmail进程的数目。它能防止系统被sendmail的任务压跨,但也让攻击者能够非常容易地关闭SMTP服务。MaxMessageSize选项有助于防止邮件队列目录被填满,但如果把它设置得太小,合法邮件将被弹回(您可以向用户说明这项限制,这样当邮件被弹回时他们就不会感到惊讶。无论如何我们建议把限制设得高一些,因为一些合法的邮件也很大)。ConnectionRateThrottle选项限制的是每秒钟内允许的连接数目,它可以大大减缓, 连接速度。最后,可以设置MaxRcptsPerMessage,它控制一则消息中允许收件人的最大数目,这可能会有所帮助。

sendmail一直能够根据系统的平均负载来拒绝链接(REFUSE_LA选项)或者把电子邮件排入队列(QUEUE_LA选项)。在8.12版的sendmail引入了一种变化(DELAY_LA选项),它能让邮件继续流动,但是速度却被降低了。参考18.12.3节关于性能的详细说明。

尽管这一切都致力于保护您的邮件系统,但用邮件轰炸您的人还是会妨碍合法的邮件传输。邮件炸弹是相当卑鄙的。

科罗拉多大学为每个学生(大约有25000人)提供了一个电子邮件账户,pine是默认的邮件阅读器。几年前,一位学生在本地的计算机商店获得了一份新工作,他的雇主说服他提供口令文件的一个副本。然后这家公司给口令文件中的每个人都发送了一则广告,大约分成每次1000个收件人(这使得To: 行非常长)这样来发。

pine是把默认的回复模式设置为对所有的收件人和发件人作出答复来编译的。许多学生用这样的问题来做答复:“为什么您给我发送这封垃圾?”。当然这样的信发给了To: 行中的其他所有人。结果是服务器拒绝所有服务?无论是电子邮件还是任何其他使用。sendmail接管了所有的CPU计算周期,邮件队列庞大无比,所有正在进行的工作都被暂停。唯一的解决方案是让这台机器下线,进入每个用户的邮件缓冲区,并删除讨厌的消息(也已经用了对标题[Subject]行进行信头检查的方法)。


伪造

伪造电子邮件在过去是小事一桩。在8.10以前,任何用户都可以伪造邮件,使得它看上去就像出自您所在的域。从sendmail 8.10开始包含SMTP身份验证,可以验证发送方机器的身份。必须用AuthMechanisms选项打开身份检查功能。遗憾的是,sendmail的身份验证功能不是端到端的,而只是在相邻的服务器之间。如果一则消息是由几台服务器处理的,那么虽然身份验证有帮助,但却不能保证不会出现伪造的消息。

类似地,在邮件消息中模仿任何用户也同样是可能的。如果邮件消息是您所在单位用于钥匙、访问卡和金钱等事情的权威传达媒介,那就要小心了。您应该用这一事实警告负责管理的用户,并建议如果他们见到的可疑邮件似乎出自某个权威人士,就应该验证该消息的有效性。如果这则消息要求把不合理的特权授予某个不寻常的人,就更要加倍小心了。如果邮件把重要的钥匙给了一个尚未毕业的大学生,这就很可疑!

authwarnings隐私选项可以标记出本地的伪造企图,它给看上去像是伪造的发出邮件添加一个Authentication-Warning信头。不过,许多用户代理程序在默认情况下会隐藏这个信头。

如果伪造的邮件出自您所控制的机器,那么您完全可以做点儿工作来阻止它。可以使用identd守护进程验证发件人的真实登录名。sendmail回叫发送的主机,要求在那台主机上运行的identd查找那个发送邮件的用户的登录名。如果远程主机上没有运行identd,sendmail将一无所获。如果远程机器是一台单用户的工作站,其拥有者就可以把identd配置成返回虚假的回答。但是如果远程主机是一台多用户机器,比如许多大学的计算中心建立的那种机器,identd就会返回该用户的真实登录名,以便sendmail把它插入到消息的信头中。

许多站点不会运行identd,它也常常被防火墙所阻挡。identd只在网点内部才真正有用,因为在您控制之外的机器可以说谎。在有某些不负责任的用户的大型网点(例如,某所大学)上,这种方法效果非常好?但是也会降低sendmail的性能。

几年前,当我们第一次试用identd时,我们站点上的一个学生对他所在高级项目组的成员感到灰心失望。他企图扮成自己的指导教师给他的队友发邮件,告诉他们他知道他们没有尽心尽力,应该工作得更卖力些。很遗憾,他犯了个语法错误,这则消息被弹回给了指导教师。sendmail使用的IDENT协议告诉了我们他是谁。sendmail在弹回的消息中包含如下几行:

 The original message was received  at  Wed,  9  Mar  1994  14:51  -0700  from
student@benji.Colorado.EDU  [128.138.126.10]
但是消息信头本身却说的另一番故事:
From:  instructor@cs.Colorado.EDU
教训:在偷偷摸摸干坏事时要避免语法错误。根据我们针对伪造邮件的政策,这个学生的登录名在那个学期的余下时间中被禁用,这刚好满足了他的愿望。他不能继续干那个项目了,他的伙伴们不得不打起精神好好工作。


消息的隐私

除非您使用外部加密软件包,比如PGP(Pretty Good Privacy)或者S/MIME,否则基本上是保证不了消息隐私的。默认情况下,所有邮件在发送时都不加密。端到端的加密要求得到邮件用户代理的支持才行。有关PGP的更多信息请参见20.11.2节。

S/MIMI和PGP都是在RFC的系列文档中说明的,S/MIME则处于标准系列。不过,我们更偏向PGP,它的使用范围更广,而且是由一位优秀的密码学专家Phil Zimmermann设计的,我们都信任他。这些行将出现的标准为邮件的机密性、身份验证、保证消息的完整性、以及发件来源的认可方面提供了一个基础。因为信头和信封仍然是以明文来发送的,所以还可以进行流量分析。

告诉您的用户,如果他们想要让自己的邮件保密,就必须自行加密。


SASL:简单的身份验证和安全层

sendmail 8.10和后继版本都支持RFC2554中定义的SMTP身份验证。它基于SASL(Simple Authentication and Security Layer,简单的身份验证和加密协议层)。SASL是一种共享秘密的系统,一般用于主机对主机的验证,您必须在彼此互相要验证对方身份的每一对服务器上明确地进行配置。

SASL是一种通用的身份验证机制,可以集成到各种协议中去。sendmail、Cyrus的imapd、Netscape、Outlook、Thunderbird和Eudora的某些版本都可以用它。SASL框架(它是一个库)有两个基本概念:一个授权标识符和一个身份验证标识符。它可以把这些标识符映射到文件权限、账号口令、Kerberos tickets等上面。SASL同时包含身份验证组件和加密组件。要配合sendmail使用SASL的话,可以从asg.web.cmu.edu/sasl获得Cyrus SASL。

TLS是在RFC2487中制定的另一种加密/验证系统。它在sendmail中是作为一种对SMTP的扩展来实现的,这叫做STARTTLS。甚至您可以SASL和TLS两者都用。

TLS设置起来要稍微困难的一点儿,它要求有证书服务。您可以向VeriSign支付一大笔钱来发布您自己的证书(标识一个实体的签名公钥),或者建立一个您自己的证书服务。它用更强的验证手段代替了主机名或者IP地址,作为授权中转邮件主机或者接受主机链接的标记。在access_db中像下面这样的配置项:

TLS_Srv:secure.example.com    ENCR:112
TLS_Clt:laptop.example.com    PERM+VERIFY:112

指出要使用STARTTLS,发送到secure.example.com这个域的邮件都必须用至少112位的密钥进行加密。从laptop.example.com这个域内的主机发来的邮件只有客户机本身通过身份验证才能接受。

Sendmail,Inc.公司的另一位员工Gregory Shapiro编写了一些有关安全和sendmail的教程,它们很不错,从www.sendmail.org/~gshapiro可以得到它们。


推荐阅读
  • 从理想主义者的内心深处萌发的技术信仰,推动了云原生技术在全球范围内的快速发展。本文将带你深入了解阿里巴巴在开源领域的贡献与成就。 ... [详细]
  • 本文介绍了Linux操作系统的核心组成部分——内核及其版本分类,以及市面上常见的几种Linux发行版,旨在为初学者提供一个清晰的学习路径。 ... [详细]
  • Ubuntu 14.04 系统安装后网卡名称修改方法
    本文介绍了在安装 Ubuntu 14.04 Server 版本后,如何将默认的网卡名称从非 eth 格式修改为传统的 eth 格式,并提供了详细的步骤和示例。 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • C++ 开发实战:实用技巧与经验分享
    C++ 开发实战:实用技巧与经验分享 ... [详细]
  • 本文探讨了有效学习专业技能的方法,包括编程语言、操作系统、软件组件及前沿技术的探索,旨在为初学者提供一套系统的自学指南。 ... [详细]
  • linux网络子系统分析(二)—— 协议栈分层框架的建立
    目录一、综述二、INET的初始化2.1INET接口注册2.2抽象实体的建立2.3代码细节分析2.3.1socket参数三、其他协议3.1PF_PACKET3.2P ... [详细]
  • 汇编语言:编程世界的始祖,连C语言都敬畏三分!
    当C语言还在萌芽阶段时,它首次接触到了汇编语言,并对其简洁性感到震惊。尽管汇编语言的指令极其简单,但它却是所有现代编程语言的基础,其重要性不言而喻。 ... [详细]
  • 如何在Mozilla Firefox中调整GIF动画的循环次数
    本文介绍了如何通过调整Mozilla Firefox的高级设置来控制GIF动画的播放次数,帮助用户根据个人喜好自定义浏览体验。 ... [详细]
  • 本文将深入探讨 Unreal Engine 4 (UE4) 中的距离场技术,包括其原理、实现细节以及在渲染中的应用。距离场技术在现代游戏引擎中用于提高光照和阴影的效果,尤其是在处理复杂几何形状时。文章将结合具体代码示例,帮助读者更好地理解和应用这一技术。 ... [详细]
  • EST:西湖大学鞠峰组污水厂病原菌与土著反硝化细菌是多重抗生素耐药基因的活跃表达者...
    点击蓝字关注我们编译:祝新宇校稿:鞠峰、袁凌论文ID原名:PathogenicandIndigenousDenitrifyingBacte ... [详细]
  • 在HTML布局中,即使将 `top: 0%` 和 `left: 0%` 设置为元素的定位属性,浏览器中仍然会出现空白填充。这个问题通常与默认的浏览器样式、盒模型或父元素的定位方式有关。为了消除这些空白,可以考虑重置浏览器的默认样式,确保父元素的定位方式正确,并检查是否有其他CSS规则影响了元素的位置。 ... [详细]
  • 在C++程序中,文档A的每一行包含一个结构体数据,其中某些字段可能包含不同数量的数字。需要将这些结构体数据逐行读取并存储到向量中,随后不仅在控制台上显示,还要输出到新创建的文档B中。希望得到指导,感谢! ... [详细]
  • 在iOS开发中,基于HTTPS协议的安全网络请求实现至关重要。HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer)是一种旨在提供安全通信的HTTP扩展,通过SSL/TLS加密技术确保数据传输的安全性和隐私性。本文将详细介绍如何在iOS应用中实现安全的HTTPS网络请求,包括证书验证、SSL握手过程以及常见安全问题的解决方法。 ... [详细]
  • 在使用 SQL Server 时,连接故障是用户最常见的问题之一。通常,连接 SQL Server 的方法有两种:一种是通过 SQL Server 自带的客户端工具,例如 SQL Server Management Studio;另一种是通过第三方应用程序或开发工具进行连接。本文将详细分析导致连接故障的常见原因,并提供相应的解决策略,帮助用户有效排除连接问题。 ... [详细]
author-avatar
mobiledu2502925687
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有