跳转到内容

保护 OpenClinica

来自 Wikibooks,开放世界中的开放书籍

保护 OpenClinca

[编辑 | 编辑源代码]

安装、配置和保护 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 服务器,因此这确实应该是您的第一道安全防线。

修改 sshd_config 文件

[编辑 | 编辑源代码]

此文件位于 `/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,可以跳到下一节(**设置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`标志来最终确定这些规则。

设置FirewallD

[编辑 | 编辑源代码]

以下配置假设您使用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软件包测试您的防火墙,以查看哪些端口已打开。

OpenClinica

[编辑 | 编辑源代码]

您已经完成了大部分使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
  1. https://tomcat.net.cn/tomcat-7.0-doc/security-howto.html
  2. http://wiki.owasp.org/index.php/Securing_tomcat
  3. http://upguard.com/articles/15-ways-to-secure-apache-tomcat-8
  4. http://geekflare.com/apache-tomcat-hardening-and-security-guide
  5. https://postgresql.ac.cn/docs/current/libpq-pgpass.html
华夏公益教科书