本文主要针对 IT 安全专业人士,介绍了如何使用 IBM WebSphere® Portal 来封装安全扫描工具。用户可以通过访问门户来请求扫描其计算机;他们将在门户或电子邮件中看到扫描的结果。您将了解如何将扫描工具与您的公司门户集成,以将其作为服务器上的一个服务运行。该工具将通过门户接口把扫描的结果提交给用户。读者应具有 Java 编程经验,并对数据库开发、Nessus 开放源代码漏洞扫描工具和 Websphere Portal 的 Portlet 开发有很好的了解。
引言
安全扫描是公司网络安全策略重要的一部分。网络管理员经常使用各种工具来扫描其用户的计算机。管理员可能会向用户发送扫描报告,然后向这些用户提供修补程序以修补安全漏洞。在这种情况下,网络用户仅以被动的方式知道其 PC 安全状态(接收到管理员通知时)。
在本文中,您将看到这样一个简单的场景:用户使用部署在WebSphere Application Server 和 WebSphere Portal 上的安全门户来按需扫描自己的计算机。将使用一个 Portlet 服务将扫描工具(在本例中为 Nessus 工具)与用户数据库集成。用户可访问安全门户来检查其计算机,扫描的结果可以在门户上获得,也可以通过电子邮件获得。图 1 显示了将此按需安全门户与 Nessus 工具及用户数据库集成的简单视图。
图 1:按需安全扫描体系结构
![图 1:按需安全扫描体系结构](https://i-blog.csdnimg.cn/blog_migrate/432d4cc7a7fce0341bbf21f9befb6e3b.png)
配置 Websphere Portal
可以配置 Websphere Portal 来通过使用 LDAP 目录进行身份验证,从而避免非授权访问。应用程序 Portlet 的业务逻辑应位于会话 Bean 层中或该层之后。您希望将访问限制为会话 Bean,因为只有相应的 LDAP 用户 ID 才能访问整个会话 Bean。有关 LDAP 的更多信息,请参阅参考资料部分。
获取 Nessus 工具
Nessus 是一个很受欢迎的开放源代码漏洞扫描程序。各个组织可以使用 Nessus 之类的工具来对业务关键型企业设备和应用程序进行审核。对于本文中描述的方案,请下载 Nessus 3.0.1 for Linux/FreeBSD。请参阅参考资料部分,以获得一个相关链接。
Nessus 服务器仅在 Linux 平台上运行。虽然在其网站上列出了一个 Windows 客户机,但对于此方案,您需要服务器端软件。(客户机版本并不提供任何服务。)
安装和配置后,就可以启动 GUI,其中提供了一个非常有用的用户界面,可以帮助扫描设备。Nessus 还提供了命令行模式,因此可以在不启动 GUI 的情况下扫描设备;所以可以使用命令行模式将 Nessus 工具与您的应用程序集成。您可以选择八种输出结果文件的方式,非常便于进行集成。清单 1 说明了 Nessus 命令行格式。
清单 1:Nessus 命令行模式
nessus -q [-pPS] <host> <port> <user> <pass> <targets-file> <result-file> [-T <format>] format: "nbe", "html", "html_graph", "text", "xml", "old-xml", "tex", or "nsr" |
要创建本文中描述的示例,请进行以下步骤:
- 在 /opt/nessus 目录中安装 Nessus 工具。
- 添加 Nessus 帐户 (jing/jing4nessus)。
- 在 /opt/nessus/host/targets.txt 中保存要扫描的主机列表。
- 运行清单 2 中所示的命令。结果文件将创建在 /opt/nessus/report/result.html 中。
请参阅 result.html 文件。
清单 2:Nessus 命令行示例
nessus -q localhost 1241 jing jing4nessus . /host/targets.txt ./report/result.html |
关于用户信息数据库
用户信息数据库存储关于公司用户的信息。如果用户通过 LDAP 身份验证,能够登录到门户,则可以从用户数据库获取其详细信息,随后可以为该用户提供一个交互会话。在此方案中,我们将检索用户的电子邮件地址,以便将扫描报告发送到此地址。本文中描述的示例使用 IBM DB2® 数据库系统。
为何使用门户?
门户可通过单个用户界面提供各种服务,且仅要求用户使用 Web 浏览器就能进行访问(假定能通过身份验证)。用户并不需要安装或配置复杂的客户机。门户经常由很多 Portlet 服务组成,这些服务将从门户接口获取请求,对请求进行操作,然后将结果返回给门户接口。这个机制可满足我们在 Portlet 中封装 Nessus 工具和用户信息数据库的需求。
创建 Portlet
每个按需扫描请求都是单线程的,需要使用一个会话 Bean 对其进行封装。可以使用 Portlet 来为每个请求创建会话 Bean。对 Nessus 工具和用户信息数据库的调用封装在两个类中。
分析 Nessus 类
Nessus 类控制 Nessus 工具并与其进行交互。将在该类中设置配置信息,以便其能够查找和调用 Nessus 工具。将创建 target
和 report
目录来存储目标和结果文件。当创建此类的新实例时,会将扫描目标和用户 ID 传递给该实例,以用于进行后续工作。这个示例将扫描程序的实例数量限制为同时可以启动五个扫描程序实例。可以根据服务器的性能配置同时启动的扫描程序实例数量。
清单 3:Nessus 类的构造函数
public class Nessus { private static final String Nessus_HOME = "/opt/nessus"; private static final String Nessus_COMMAND="bin/nessus"; private static final String Nessus_AUTH_INFO= "-q localhost 1241 jing jing4nessus"; private static final String Nessus_TARGET_DIR="target"; private static final String Nessus_REPORT_DIR="report"; private static final String PATH_SEPARATOR="/"; public static final int Nessus_MAX_Cient = 5; public static int Nessus_Client = 0; private String result; private lastErrorMessage=""; private String[] Nessus_HOST; private String UserID; public Nessus(String[] Nessus_HOST, String UserID) { while (Nessus_Client >= 5){}; ++Nessus_Client; Nessus_HOST = inNessus_HOST; UserID = inUserID; } public dispose() { if (Nessus_Client > 0) { --Nessus_Client; } } ...... } |
创建了 Nessus 类实例后,需要对其进行初始化。Nessus 工具需要一个目标文件作为参数,以便进行扫描。目标文件包含一个要扫描的 IP/主机名列表。我使用名为 Nessus_HOST
的字段装配一个文件(如清单 4 中所示),然后将其存储到名为 target
的目录中。
清单 4:初始化 Nessus 类实例
public int init();{ String Nessus_HOSTs=""; for (int i=0;i<Nessus_HOST.length;++i) { Nessus_HOSTs+=Nessus_HOST[i]+"/n"; } try { String filename = Nessus_HOME + PATH_SEPARATOR + Nessus_TARGET_DIR + PATH_SEPARATOR + UserID File file = new File(filename); if (file.exist()) { file.delete(); } BufferedWriter fileDesc = new BufferedWriter(new FileWriter(filename)); fileDesc.write(Nessus_HOSTs); fileDesc.close(); fileDesc = null; } catch { lastErrorMessage="Init failed!"; return 1; } return 0; } |
Nessus 类的核心方法 scanTarget() 使用命令行接口调用 Nessus 工具。该方法将挂起,直到 Nessus 工具返回结果为止,该方法将随后把结果存储在 result
目录中。
清单 5:扫描目标目录
public int scanTarget() { String targetfile = Nessus_HOME + PATH_SEPARATOR + Nessus_TARGET_DIR + PATH_SEPARATOR + UserID; String reportfile= Nessus_HOME + PATH_SEPARATOR + Nessus_REPORT_DIR + PATH_SEPARATOR + UserID+".html"; String command = Nessus_HOME + PATH_SEPARATOR + Nessus_COMMAND + PATH_SEPARATOR + Nessus_AUTH_INFO + PATH_SEPARATOR + targetfile + PATH_SEPARATOR + reportfile; try { Process process = Runtime.getRuntime().exec(command); InputStreamReader ir=new InputStreamReader(process.getInputStream()); LineNumberReader input = new LineNumberReader(ir); while (input.readLine() != null); } catch (IOException ex) { lastErrorMessage = "Scan failed"; return 1; } result = reportfile; return 0; } public String getResult() { return result; } |
分析 UserInfo 类
UserInfo 类控制用户信息数据库并与之进行交互。在此示例中,该类将从数据库检索电子邮件地址,以便使用其将结果发送给用户。所有查询将共享单个连接,以减少资源浪费。
清单 6:UserInfo 示例
public class UserInfo { private static final String DB2_JDBC_DRIVER = "COM.ibm.db2.jdbc.app.DB2Driver"; private static final String UserInfo_DB_URL = "jdbc:db2:userinfo"; private static final String UserInfo_DB_USER = "db2inst1"; private static final String UserInfo_DB_PASS = "password"; private Static Connection con; private Static UserInfo userinfo; private Static reference=0; private UserInfo() { } public static UserInfo getUserInfo() { if (userinfo == null) { userinfo = new UserInfo(); try { Class.forName(DB2_JDBC_DRIVER); } catch(java.lang.ClassNotFoundException e) { lastErrorMessage = "DB connect error!"; return null; } try { con = DriverManager.getConnection(UserInfo_DB_URL, UserInfo_DB_USER, UserInfo_DB_PASS); } catch (SQLException ex) { lastErrorMessage = "DB login error!"; return null; } } return userinfo; } public int dispose() { try { con.close(); } catch (SQLException ex) { lastErrorMessage = "DB connect error!"; return 1; } return 0; } public String getEmail(String UserID) { While (reference>0) ; ++reference; String sql; sql = "select email from userinfo where id = " + UserID; Statement stmt; String result; try { stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); while(rs.next()){ result = rs.getString(0); } stmt.close(); } catch(SQLException ex) { lastErrorMessage = "DB query error!"; result = null; } --reference; return result; } } |
由于每个按需扫描都是单线程的,因此将创建会话 Bean 来封装 Nessus 类,以向 Portlet 提供会话接口。清单 7 显示了相应的原型。
清单 7:会话 Bean 原型
public class OnDemandScanPortletSessionBean { private Nessus nessus; private UserInfo userinfo; public int setUserID(String inUserID); public int setTarget(String[] inNessus_HOST); public Nessus getNessus(); public UserInfo getUserInfo(); public String getEmailAddress(); |
![]() ![]() |
![]()
|
显示结果
可以对结果门户页进行设计,以使其满足您自己的接口需求,然后将结果 html 嵌入到页面中。图 2 和图 3 显示了两个扫描结果示例。图 2 以 HTML 格式显示结果,而图 3 以 HTML_graph 格式显示结果。
图 2:HTML 格式的扫描结果
![图 2:HTML 格式的扫描结果](https://i-blog.csdnimg.cn/blog_migrate/7af32186cbca5fe9db7d19e42d1accdd.png)
图 3:HTML_graph 格式的扫描结果
![图 3:HTML_graph 格式的扫描结果](https://i-blog.csdnimg.cn/blog_migrate/5b7d0561fe86b9460d391d7cfa8645c9.png)
![]() ![]() |
![]()
|
结束语
现在您可以使用门户接口构建自己的按需扫描服务器了。您可以将各种工具(包括仅在一个平台上——在本文的示例中为 Linux——运行的工具)与公司的门户集成,从而向用户提供新服务。向用户提供按需扫描功能可以帮助您的公司达到其安全策略的要求。