保护 OpenClinica
安装、配置和保护 OpenClinica [OC] 社区版 [CE] 绝对是一次冒险,需要掌握计算机科学各个方面的知识。但是,通过大量的谷歌搜索和奉献精神,任何对 Linux 有一定了解的人都可以做到。我并非计算机科学专业人士,但仍然承担了在 Web 服务器上部署 OC 的任务,最终成功地使其运行起来。不过,也有一些时候,我希望有一份关于如何管理此过程的详尽指南。通过这篇文章,我想填补这一空白,至少在 OC 的安全方面,为任何尝试执行相同任务的人提供帮助。
我采取的措施是从众多来源中找到的,我不能保证这些措施涵盖了保护 OC 时可以/应该采取的所有措施。正如我之前提到的,我不是该领域的专家,本指南仅仅是我大量搜索和反复试验的结果。请谨慎对待这里的所有内容,如果您认为自己有更好的方法,请不要犹豫进行更改。也请随时建议改进/增加此过程,以便我们都能从这些集体知识中受益。
我尽可能认真地对待安全性,因为截至 2020 年,OC CE 所需的软件早已过时,因此尽一切可能使其安全至关重要,尤其是在处理患者数据时。
我选择的设置如下
- OpenClinica CE 3.15
- CentOS 8
- PostgreSQL 8.4.22
- Tomcat 7.0.52
- JVM 1.7.0
我按照 此安装指南 进行操作,因为我找不到 v3.15 的指南。获得上面列出的一些特定软件版本颇具挑战性,如果我不得不重新开始,我会考虑使用 CentOS 6,因为此版本原生支持其中一些较旧的依赖项。CentOS 6 也已于今年停止支持,因此在选择它时请仔细考虑。
根据上述指南的指示,运行 OC 所需的所有组件的根文件夹位于:/usr/local
话不多说,我们开始吧
首先,访问 Web 服务器(如果是远程服务器)应该得到保护。每天都有数百次尝试使用常见用户名登录 Web 服务器,因此这确实应该是您的第一道安全防线。
此文件位于 `/etc/ssh/sshd_config` 下,并控制对服务器的 SSH 访问。在对其进行任何更改之前,请确保已对其进行了备份。在文件中,修改以下参数
仅允许需要访问服务器的用户
- AllowUsers <username1> <username2>
禁用 root 登录
- PermitRootLogin no
- ChallengeResponseAuthentication no
将您的 SSH 密钥复制到服务器后(使用 ssh-copy-id 或手动,通过复制您的公钥并将其粘贴到服务器上的 `~/.ssh/authorized_keys` 文件中),您应该禁用密码身份验证。这样,仅可以通过 SSH 密钥身份验证登录。
- PasswordAuthentication no
为了提高安全性,还可以将 UsePAM 设置为 `no`,但是,这会弄乱我的 SSH 身份验证过程,我不得不将其设置回 `yes`。
所有内容配置完成后,重新启动 sshd 服务
sudo systemctl restart sshd
此软件包通过禁止在 x 次身份验证失败后尝试 SSH 身份验证的 IP 地址来提供额外的 SSH 安全性。这里有一篇关于配置 fail2ban 的 很棒的指南。
sudo yum install epel-release
sudo yum install fail2ban
在 `/etc/fail2ban` 下创建一个名为 `jail.local` 的文件,并将以下内容粘贴到其中(使用您自己的电子邮件地址)
[DEFAULT] # Ban hosts for one hour: bantime = 3600 maxretry = 5 [sshd] enabled = true destemail = <[email protected]> sender = <[email protected]> sendername = Fail2ban mta = sendmail action = %(action_mwl)s
创建此文件而不是直接在 `jail.conf` 中进行配置是首选,因为 fail2ban 更新会覆盖您的配置。现在,当 IP 地址在 5 次失败的登录尝试后被禁止或 fail2ban 被停止/启动时,您将收到电子邮件通知。
重新启动 fail2ban 服务:sudo systemctl restart fail2ban
如果您想接收有关被禁止 IP 的更多信息,可以安装 `whoami.x86_64` 软件包。
您可以通过以下方式检查 sshd 监禁状态:sudo fail2ban status sshd
虽然这听起来可能很明显,但仍然至关重要的是在您的服务器上维护强大且唯一的密码。我建议使用 KeePass 来跟踪它们,因为它还允许您自动生成非常强大的密码。
保护 Tomcat 与保护您的 Web 服务器一样重要,因为这是您与外部世界的联系点。我从以下网站收集了下面列出的安全措施 [1] [2] [3] [4]
这是为了确保即使攻击者能够控制 Web 服务器,她所能造成的损害也是最小的。首先,永远不要以 root 用户身份运行您的 Web 服务器,创建一个名为 `tomcat` 的新用户,该用户具有运行服务器的最低必要权限。
将文件夹 `tomcat` 及其所有内容的所有者设置为用户 tomcat 和组 tomcat
chown -R tomcat:tomcat /usr/local/tomcat
(没有 -R 标志,您只会更改文件夹的所有权,而不是内容)
授予文件夹所有者读取、写入和执行权限
chmod -R 700 /usr/local/tomcat
(关于使用 chmod 的指南:https://www.lifewire.com/uses-of-command-chmod-2201064) 注意:要能够打开文件夹,您需要对它具有执行权限。我也有过惨痛的教训。
从配置文件夹中删除写入和执行权限。这可以防止攻击者修改 Tomcat 的配置文件
chmod -R u-wx /usr/local/tomcat/conf
但是,Tomcat 需要能够打开文件夹,因此仅向文件夹添加执行权限(=不带 -R 标志)
chmod u+x /usr/local/tomcat/conf
从 openclinica.config 和 openclinica-ws.config(如果已安装)文件夹中删除读取权限
chmod -R u-w openclinica*.config
从 logs 文件夹中删除读取权限
chmod -R u-r /usr/local/tomcat/logs
删除 oldwebapps 文件夹的所有权限,因为在部署过程中 Tomcat 不需要处理这些文件。
chmod -R u-rwx /usr/local/tomcat/oldwebapps
将 `datainfo.properties` 文件设置为只读(如果安装了 OpenClinica-ws,也对它执行同样的操作)。
chmod 400 /usr/local/tomcat/webapps/OpenClinica/WEB-INF/classes/datainfo.properties
至此,Tomcat 的访问控制方面已完成。
还可以做的一件事是将您的用户添加到 tomcat 组,并授予该组对 usr/local/tomcat 文件夹的读写执行权限。这样,您仍然可以方便地编辑所有内容,而无需使用 root/sudo。我对它的安全方面确实不确定,请自行承担风险使用。并且不要忘记在所有配置完成后,将自己从组中移除并删除权限。
HTTPS
如上所述,Tomcat 的 SSL 设置指南应该是您首先要做的步骤(https://tomcat.net.cn/tomcat-7.0-doc/ssl-howto.html)。您必须确保本指南中列出的所有步骤都使用 `tomcat` 用户执行,因为如果以其他用户身份执行,则 .keystore 文件将创建在该用户的 home 目录下,Tomcat 将无法找到并读取它。理论上,您也可以注释掉 HTTP 连接器,因为强制使用 HTTPS 访问 OC 是最佳实践。端口转发将在防火墙级别启用,因此理论上 Tomcat 永远不会收到对端口 8080 的请求,但我还没有实际测试过。
配置完成后,您应该能够使用 HTTPS 与您的 Web 服务器通信(在 https://127.0.0.1:8443/OpenClinica 上)。如果您使用的是自签名证书,您的浏览器会发出警告,但您仍然可以访问该站点。您可以在 Tomcat 中强制使用 HTTPS,方法是在 `tomcat/conf` 下的 web.xml 文件末尾添加以下内容(在 `` 标记之前)
<security-constraint> <web-resource-collection> <web-resource-name>Protected Context</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
Cookie、自定义错误页面、禁用列表等
这些是良好的实践,但不是必须的。这些包括隐藏错误页面中的服务器版本或禁用文件系统列表,以更好地保护您免受 DDoS 攻击。
以下所有内容都需要添加到 `web.xml` 文件中。
安全且仅限 HTTP 的 Cookie,以防止 XSS 攻击
(粘贴到 `` 标记之前)
<cookie-config> <http-only>true</http-only> <secure>true</secure> </cookie-config>
自定义错误页面
(粘贴到 `` 标记之前)(由于 Tomcat 无法找到错误页面文件,因此不会显示任何错误页面,但它确实通过隐藏版本号完成了工作。如果这对您来说是个问题,请跳过此步骤。)
<error-page> <error-code>404</error-code> <location>/error.jsp</location> </error-page> <error-page> <error-code>403</error-code> <location>/error.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/error.jsp</location> </error-page> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/error.jsp</location> </error-page> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/error.jsp</location> </error-page>
只读资源和无列表
(粘贴到文件中的 `DefaultServlet` 部分)
<init-param> <param-name>readonly</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param>
server.xml
移除服务器标语
如果在连接器的参数列表中添加 `Server=" "` 参数,则会隐藏 HTTP 标头中的版本号。它应该看起来像这样
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" Server =" " address="<webserver IP address or localhost>" clientAuth="false" sslProtocol="TLS" keystoreFile="${user.home}/.keystore" keystorePass="<your keystore pass>" />
更改关闭命令
为了防止攻击者能够关闭您的服务器,您应该考虑更改关闭端口以及关闭命令。您可以在 `server.xml` 文件开头,`` 标记内执行此操作。
AJP 连接器
如果 OC 是唯一将部署到 Tomcat 中的 Web 应用程序,您可以安全地注释掉 AJP 连接器行,因为 OC 没有使用此连接器。
可能良好的实践,但对我造成了问题
禁用自动部署
为了防止有人在您的 Tomcat 实例中自动部署他们自己的恶意 Web 应用程序,您可以在 `server.xml` 文件中关闭自动部署,方法是在 `` 标记内将以下参数设置为 false。
autoDeploy="false" deployOnStartup="false" deployXML="false"
这样,如果重新启动服务器,则必须手动部署 OC,您需要弄清楚如何操作。
安全容器
使用 Tomcat,您可以选择在一个容器中启动您的实例,这确保了即使在最坏的情况下有人入侵服务器,他们也只能访问此容器内的资源和文件。但是,您需要花费时间才能使它在 OC 上工作,因为它已知会(并且对我来说)破坏安装。如果您有时间和知识使其工作,那么这可能是值得的。
否则,用法非常简单,在启动 Web 服务器时添加 `-secure` 标志
/usr/local/tomcat/bin/startup.sh -secure
Tomcat 部分到此结束。
PostgreSQL
在安全性方面,您可以为 PostgreSQL 配置的内容不多,但也可以进行一些访问控制。
更改 pgsql 文件夹的所有权
sudo chown -R postgres:postgres /usr/local/pgsql
更改权限
sudo chmod -R 700 /usr/local/pgsql
您还应该仔细配置 `/usr/local/pgsql/data/` 中的 `pg_hba.conf` 文件。此文件控制对数据库的不同访问权限。您需要为本地连接的 clinica 用户授予对 openclinica 数据库的访问权限,但阻止所有其他连接尝试。身份验证方法应设置为 `md5`,切勿使用 `password`,因为它会以明文形式发送密码。如果要从远程机器直接访问数据库,则需要在此处添加相应的行。
# TYPE DATABASE USER CIDR-ADDRESS METHOD # allow user clinica to connect to openclinica locally, using encrypted password based authentication (needed to automate backups) local openclinica clinica md5 # IPv4 local connections: host openclinica clinica 127.0.0.1/32 md5 # "local" is for Unix domain socket connections only local all all reject # IPv6 local connections: host all all ::1/128 reject
此配置对于下面将描述的自动备份也很重要。
防火墙
为任何 Web 服务器设置防火墙都是必须的。这允许您限制和监控服务器与外部世界之间发生的所有流量。此处的主要目标是仅打开 Web 应用程序正常运行所需的端口。在本例中,这意味着
- 端口 80/tcp,预期接收传入的 HTTP 流量,
- 端口 443/tcp,预期接收传入的 HTTPS 流量,
- 端口 22/tcp,SSH 流量正在进行。
您可能需要进行一些尝试和错误,以查看关闭某个端口是否会中断任何内容,但对我来说,仅允许这 3 个端口即可。
如果您已经熟悉使用FirewallD,可以跳到下一节(**设置FirewallD**)。
CentOS预装了FirewallD,这是一个强大的工具,用于管理这些连接。网上有很多资源可以帮助您了解更多信息,例如这个。
(更新:本文中描述的一种现象已过时。无法由其分配的区域处理的数据包不会“向上踢”到下一个区域(“区域漂移”的概念)。它被认为是不安全的,将在未来版本的FirewallD中移除。如果您确实希望拥有此行为,可以在FirewallD的配置文件中启用区域漂移)
首先确保firewalld已安装并在您的系统上启用。启用的默认区域是`Public`,出于我们的目的,您可以保持这种方式。您可以检查此区域中默认启用了哪些服务
sudo firewall-cmd --zone=public --list-all
服务不是一些特殊的实体,它们仅仅代表给定服务能够正常运行所需的开放端口。这些在`/usr/lib/firewalld/services`下定义为不言自明的xml文件。如果您想定义自己的服务,可以通过将这些xml文件之一复制到`/etc/firewalld/services`并根据自己的需要自定义它来实现。您可以通过以下方式将任何服务添加到防火墙区域
sudo firewall-cmd --zone=public --add-service=<您的服务> --permanent
您可以通过以下方式删除任何不必要的服务
sudo firewall-cmd --zone=public --remove-service=<不必要的服务> --permanent
您还可以直接添加/删除所需的端口
firewall-cmd --zone=public --add-port=<您的自定义端口号>/tcp --permanent
如果没有`permanent`标志,一旦FirewallD重新加载或重启,更改将被重置。您可以在没有标志的情况下试验规则,一旦您发现适合您的规则,就可以通过添加`--permanent`标志来最终确定这些规则。
以下配置假设您使用ssh访问远程服务器,但是,如果不是这种情况,您可以跳过设置内部区域。
防火墙将设置三个区域:public、internal和trusted。public应处理来自任何请求IP地址的所有http/s请求。internal区域应添加一个源,其中包含您的IP或MAC地址,因此(理论上)只有当您的机器与服务器通信时,此区域才会处理数据传输。这也是启用了ssh服务的区域(=打开端口22)。
在开始配置FirewallD之前,您应该确保iptables已禁用并阻止其通过屏蔽它而启动。否则它可能会干扰FirewallD并导致一些奇怪的行为。
systemctl mask iptables
systemctl disable iptables
首先从public和internal区域删除任何不必要的服务。使用`--list-all`标志查看当前允许的内容。您应该只保留(或添加,如果需要)http/https。在internal区域中,还要添加ssh服务。
您应该将面向外部的网络接口分配到public区域(因此来自外部的所有请求都将由此区域处理)。您可以通过以下方式列出所有可用的接口
ip link show
您可以使用`--add-interface=<接口>`标志添加接口。
不幸的是,这些接口的命名并不简单(至少对我来说,我的叫`ens192`),因此您可能需要做一些研究才能了解情况。
您还应该将自己的IP/MAC添加到internal区域的源中,以便只有来自此IP/MAC地址的请求才会由此区域处理,例如
sudo firewall-cmd --zone=internal --permanent --add-source=154.112.12.18
如果您希望从某个特定的VPN使用ssh,也可以使此IP更通用
sudo firewall-cmd --zone=internal --permanent --add-source=154.112.0.0/16
这将允许154.112.0.0-154.112.255.255中的任何人使用ssh。(请注意,只有当至少分配了一个接口或源时,区域才会处于活动状态!)
public区域的目标应设置为DROP,这在请求到达无效端口时不会返回任何消息,而不是传输拒绝消息。这被认为更安全。
sudo firewall-cmd --permanent --zone=public --set-target=DROP
接下来,创建端口转发规则以限制与https的通信,并适应Tomcat的端口约定(它使用8080而不是80,使用8443而不是443)
sudo firewall-cmd --zone=public --permanent --add-forward-port=port=443:proto=tcp:toport=8443 sudo firewall-cmd --zone=public --permanent --add-forward-port=port=80:proto=tcp:toport=8443 sudo firewall-cmd --zone=internal --permanent --add-forward-port=port=443:proto=tcp:toport=8443 sudo firewall-cmd --zone=internal --permanent --add-forward-port=port=80:proto=tcp:toport=8443
要使端口转发工作,您还需要启用伪装(https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-port_forwarding)
sudo firewall-cmd --zone=public --add-masquerade --permanent
sudo firewall-cmd --zone=internal --add-masquerade --permanent
现在这一步我比较不确定,因为我找不到太多关于它的信息。我将lo(环回)接口分配到trusted区域。这是从同一台机器(localhost,127.0.0.1)与您的Web服务器通信的接口。理想情况下,这是外部世界无法访问的,因此我假设trusted区域适合它,但同样,我在这里可能错了。
如果您需要ping工作,请运行此命令(将区域替换为您需要ping工作的区域)
sudo firewall-cmd --permanent --zone=<您的ping区域> --add-rich-rule='rule protocol value="icmp" accept'
您必须重新加载firewalld才能使更改生效
sudo firewall-cmd --reload
现在您已将FirewallD配置为仅允许与外部世界的http/s通信,但仍允许从您的个人计算机/您的VPN网络建立ssh连接。
您可以使用nmap软件包测试您的防火墙,以查看哪些端口已打开。
您已经完成了大部分使OC安全的工作,但您仍然可以在OC本身中做一些事情。如果您以root身份登录Web界面,导航到`任务/管理/用户/配置密码要求`,将有一些选项可以打开/关闭并调整以满足您的需求。您还应该在尝试x次后启用用户锁定(`任务/管理/用户/锁定`)。作为root,如果用户帐户被锁定,您可以在Web界面上解锁这些帐户。我自己采取的另一项措施,但不确定是否必要:要求我的OpenClinica实例的用户将他们的密码挑战问题设置为一个长(不可猜测)的字符串。我这样做是因为我不确定OC如何发送密码重置电子邮件,以及此电子邮件是否可能被潜在攻击者劫持。一个更安全(尽管承认更不方便,如果您有太多用户甚至不切实际)的解决方案是以root身份从Web界面重置用户的密码并自行发送给他们。
这确实也应该是必须的。我在这里分享的解决方案只是一种方法,如果您有更好的方法,请随时按照自己的方式操作。
这里有一份指南是关于如何在OC中实施备份的指南。基本上,您希望定期保存您的OC配置文件、您的研究目录($TOMCAT_ROOT/openclinica.data)和您的PostgreSQL数据库。
我附加了一个脚本,如果执行该脚本,它应该备份所有这些内容,将它们打包成一个tarball文件并将其保存到`/usr/local/OpenClinica_backups`。您可以(也应该)通过编辑脚本中的BCKP_path变量来更改备份位置以使其位于服务器外部。此外,您还需要创建一个.pgpass文件才能使其工作,更多详细信息如下。
我对上述链接指南的补充是使这些备份自动发生,例如每天一次。为此,我使用了`cron`服务,该服务在CentOS 8上预装。
要使您的脚本每天执行,请将其放在`/etc/cron.daily/`下。通常,要能够获取pg_dump,您需要openclinica数据库的密码。要允许自动更新,您需要在`/var/lib/pgsql/`下创建.pgpass文件。其内容应如下所示
localhost:5432:openclinica:clinica:<您的数据库密码>
为了使Postgres能够使用此文件,它必须由postgres拥有
sudo chown postgres:postgres .pgpass
并且其权限必须设置为0600
sudo chmod 0600 .pgpass
如果您在身份验证方面遇到任何问题,请参阅pgpass的文档[5]。
为了能够创建pg_dump,postgres需要能够写入您的备份文件夹。将文件夹的组更改为postgres并授予组rwx权限
sudo chown root:postgres <您的备份文件夹>
sudo chmod g+rwx <您的备份文件夹>
您应该练习恢复数据库以了解它是如何实际完成的。上面提到的指南可以帮助您完成此操作。
有一个优秀的GitHub仓库,它允许您运行每日扫描以检测各种恶意软件,包括特洛伊木马、病毒或rootkit。如果您将克隆存储库中的脚本放在/etc/cron.daily
下。它将与自动备份脚本一起每天执行。
为了清楚起见,最好禁用tomcat、clinica和postgres用户的登录
usermode -L tomcat usermode -L clinica usermode -L postgres
干得好,您刚刚使您的 OpenClinica 安装更加安全!不幸的是,您必须记住,我们一直在加固的软件是过时的软件(非常过时),因此您只能做这么多并希望一切顺利。我所能给出的最佳建议是,如果可能,不要包含受试者的信息,这些信息可以识别他们。这样,即使一切失败,至少您的受试者也不必担心个人身份盗窃。
#! BCKP_path='/usr/local/OpenClinica_backups' DATE=`date +"%Y-%m-%d"` cd $BCKP_path # create a database dump with pg_dump sudo -u postgres /usr/local/pgsql/bin/pg_dump -U clinica openclinica -w > pg_dump # backup the data directory of OC with CRF, XML, etc.. data sudo tar -cf oc_data.tar /usr/local/tomcat/openclinica.data # backup OC configuration sudo cp /usr/local/tomcat/openclinica.config/datainfo.properties datainfo.properties # tar all the above created files and assign a date sudo tar -czf ${DATE}_openclinica_backup.tar.gz datainfo.properties oc_data.tar pg_dump # remove created temporary files sudo rm datainfo.properties sudo rm oc_data.tar sudo rm pg_dump # add a bit of security sudo chmod 400 *.tar.gz