有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Hibernate身份验证,不使用明文存储的密码

我的目标是以安全的方式使用JDBC/Hibernate对数据库进行身份验证,而无需以明文形式存储密码。代码示例。我已经在使用waffle对用户进行身份验证,所以如果有某种方法可以使用waffle从用户那里获得的凭据,并将这些凭据转发给数据库,那就好了

两个问题:

  1. 使用web服务器上的tomcat/hibernate/spring、sql数据库和客户端浏览器进行多跳身份验证(客户端、web服务器和数据库都是不同的机器)的推荐方法是什么
  2. 我也会满足于使用单个用户帐户进行身份验证的方式,只要该用户帐户的信息不以纯文本形式存储在任何地方。用户帐户需要对数据库具有读/写权限

我发现了一些有关连接到SQL Serverin this thread的有用信息。但是,我希望Tomcat将在默认帐户下运行,比如本地系统或其他什么。据我所知,该帐户不能用于对数据库进行windows身份验证

我的解决方案

我最终使用了上述线程中提到的方法。Tomcat服务不再作为本地系统运行,而是作为用户运行。该用户具有访问数据库的权限。我的hibernate配置文件配置如下:

    <property name="hibernate.connection.url">
jdbc:sqlserver://system:port;databaseName=myDb;integratedSecurity=true;
</property>

给那些提供回复的人

我非常感谢大家的帮助,我将尝试线程中提到的一些技术。我对一些响应的问题是,它们需要对称加密,而对称加密需要密钥。将密钥保密与将密码存储在纯文本中几乎是完全相同的问题


共 (6) 个答案

  1. # 1 楼答案

    如果我理解正确,您的环境是部署在tomcat中的基于hibernate框架的web应用程序

    现在,您必须已经配置了JDBC Passbrow i) 在属性中的hibernate配置文件(通常为hibernate.cfg.xml文件)中:-

    冬眠。联系密码

    ii)或在tomcat配置文件中:-

    <Resource name="jdbc/myoracle" ......password="tiger".../>
    

    现在,您不希望在上述任何文件中存储清除密码

    在应用程序代码中,您必须执行以下操作:-

    Line1: org.hibernate.cfs.Condiguration configuration=new Configraution().configure(<hibernate configuration path>);
    
    then,Line2:  configuration.buildSessionFactory().openSession() to create a hibernate session which has underlying JDBC connection.
    

    1)一种方式基本上可以是:- 您可以使用任何JCE提供程序,使用任何java安全算法对密码进行加密。您可以将加密密码存储在上述任何配置文件中(根据您的项目环境使用hibernate或tomcat)

    然后在第1行和第2行之间,可以有如下解密逻辑:-

    Line1: org.hibernate.cfs.Condiguration configuration=new Configraution().configure(<hibernate configuration path>);
    
    String encrpytedPassword=
    configuration.getProperty("hibernate.connection.password"); \\will return encrypted password
    
    //decryption logic to decypt the encrypted password:-
    String decryptedPwd=decrypt(encrpytedPassword);
    
    configuration.setProperty("hibernate.connection.password",decryptedPwd);
    
    then,Line2:  configuration.buildSessionFactory().openSession()
    

    您可以使加密和解密尽可能复杂,例如,对清除密码的反向字符串进行加密。 您可以使用任何JCE API:-jasrypt,bouncy castle。 您应该需要对java加密有一些了解。请参阅:

    http://download.oracle.com/javase/1.4.2/docs/guide/security/CryptoSpec.html

    2)如果您担心密码在JDBC连接协议中以明文形式传输,那么您可以使用DB provider提供的SSL支持来保护连接。例如,与数据库服务器建立SSL JDBC连接。有关此信息,请参阅数据库服务器资源

    EDITED TO CLARIFY keylM's comment ON HOW TO ENCRYPT THE JDBC PASSWORD

    假设您有一对私钥和公钥:=privare。密钥和公共密钥。cer。 您可以使用私钥对JDBC密码进行加密,并将加密的密码保存在配置文件中。您可以使用OpenSSL将公共证书导入jks(java密钥库)文件,并将其保存在java_HOME\jre\lib\security中

    在解密逻辑中:-

      KeyStore ks = KeyStore.getInstance("JKS");
      ks.load(new FileInputStream("keystore.jks"),<jks password>); //jks password can be hardoded
    Certificate cert=      ks.getCertificate(<certificate alias>);
    //use certificate to decrypt the encrypted password
    

    因此,在这种情况下:- 黑客需要3样东西才能获取JDBC密码,从而降低系统的易受攻击性:- i) 加密JDBC密码 ii)JKS商店 iii)JKS存储密码

    你们可能会问这样一个问题,那个么JKS存储密码呢,不管是密钥、密码短语还是密码,在加密解密系统中,至少有一件事应该是高度安全的;否则会危及整个系统。。。。在上面的场景中,可以向每个开发人员机器提供证书,让他导入到由相同jks存储密码保护的jks文件中。。每个人(开发人员)都只知道JKS存储密码,但从来不知道JDBC密码

  2. # 2 楼答案

    好的,让我们来看看这个问题。您希望使身份验证信息可用,但不要在代码或文件系统中的任何位置硬编码。我的建议是:

    • 要求应用程序管理员在应用程序启动时通过jmx或不需要任何数据库连接的网页指定身份验证信息
    • 添加servlet过滤器以限制访问,直到输入数据库身份验证信息

    此解决方案确实需要一些扩展的spring上下文加载,以便等待指定身份验证信息(通过入口页面)

  3. # 3 楼答案

    为了能够使用hibernate透明地加密/解密数据库中的密码,您需要集成类似Jasypt的东西

    主页:www.jasypt。组织机构 参见第节:Jasypt+Hibernate 3

    以下是如何整合它:

    1. 下载jasypt。jar并将其添加到运行时类路径中

    2. 我建议使用注册的加密机:

    <typedef name="encrypted" class="org.jasypt.hibernate.type.EncryptedStringType">
      <param name="encryptorRegisteredName">strongHibernateStringEncryptor</param>
    </typedef>
    <class name="User" table="USER">
      <property name="password" column="PASSWORD" type="encrypted" />
    <class>
    

  4. # 4 楼答案

    我最近{a1}:

    您可以告诉tomcat的jdbcrealm对密码(如sha-256)使用摘要算法,并保存哈希而不是明文密码

    假设您的用户实体如下所示:

    @Entity
    @Table(name = "cr_users")
    public class UserDetails{
        @Id
        @GeneratedValue
        private long id;
        private String name;
        private String passwordHash;
        @ManyToMany
        private Set<Group> groups;
    }
    

    通过服务创建新用户时,可以使用MessageDigest创建密码哈希:

    public UserDetails createNewUser(String username,String passwd,Set<Group> groups){
           UserDetails u=new UserDetails();
           u.setname(username);
           u.setGroups(groups);
           u.setPassword(createHash(passwd));
           return u;
    }
    public String createHash(String data){
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            digest.update(password.getBytes());
            byte byteData[] = digest.digest();
            //convert bytes to hex chars
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < byteData.length; i++) {
             sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
            }
            return sb.toString();
    }
    

    由于SHA-256总是为相同的输入生成相同的hashvalue,您可以告诉tomcat的JDBCRealm使用此算法来验证密码

    <Realm className="org.apache.catalina.realm.JDBCRealm"
           driverName="org.postgresql.Driver"
           connectionURL="jdbc:postgresql://localhost:5432/mydb"
           connectionName="myuser" connectionPassword="mypass"
           userTable="tc_realm_users" userNameCol="username" userCredCol="passwordhash" 
           userRoleTable="tc_realm_groups" roleNameCol="groupname"
           digest="sha-256"/>
    

    问题是tomcat希望usertable有一种不同的格式,如下所示:

    +----------------------+  +-------------------+
    |   tc_realm_users     |  | tc_realm_groups   |
    +----------------------+  +-------------------+
    | username     varchar |  | username  varchar |
    | passwordhash varchar |  | groupname varchar |
    +----------------------+  +-------------------+
    

    如果您的用户数据模型适合您,那么您很幸运,但我的Hibernate生成的表如下所示:

    +----------------------+  +-------------------+  +--------------------+
    |     cr_users         |  |      cr_groups    |  | cr_users_cr_groups |
    +----------------------+  +-------------------+  +--------------------+
    | id              long |  | id           long |  | cr_users_id   long |
    | name         varchar |  | name      varchar |  | groups_id     long |
    | passwordhash varchar |  +-------------------+  +--------------------+
    +----------------------+
    

    因此,我使用SQL创建了一个View,该SQL具有预期的格式,并从我的webapps用户数据中提取数据:

    create view tc_realm_groups as
    select 
      cr_users.name as username,
      groups.name as groupname
    from cr_users 
    left join (
            select 
                    cr_users_cr_groups.cr_users_id,cr_groups.name 
            from cr_groups 
            left join 
                    cr_users_cr_groups 
                    on cr_users_cr_groups.groups_id=cr_groups.id
    ) as groups on groups.cr_users_id=id;
    
    create view tc_realm_users as
    select 
      name as username
    from cr_users;
    

    有了它,tomcat能够对我已经存在的用户数据进行身份验证/授权,并在上下文中写入数据,以便我可以在我的Jersey (JSR-311)资源中使用它:

    public Response getEvent(@Context SecurityContext sc,@PathParam("id") long id) {
                    log.debug("auth: " + sc.getAuthenticationScheme());
                    log.debug("user: " + sc.getUserPrincipal().getName()); // the username!
                    log.debug("admin-privileges: " + sc.isUserInRole("webapp-admin"));
                    return Response.ok(“auth success”).build();
            }
    

    还有一些其他领域的实现:

    • JDBCRealm
    • 数据源
    • JNDIRealm
    • 用户数据库领域
    • 记忆财产
    • JAASRealm
    • 组合式住宅
    • 锁国

    一些链接:

  5. # 5 楼答案

    通常,这是使用“系统管理员”方法处理的-使用操作系统:

    基本概念是“外部化配置参数”。 密码以明文形式存储在“属性文件”(web服务器在运行时访问该文件)中。通过使用操作系统级文件权限限制对文件的访问来保护密码。通常,只有“操作”人员可以读/写文件,web服务器需要以文件的只读权限运行

    这种方法的好处是:

    • 易于理解和实现(无需输入加密值)
    • 由专为保护而设计的软件保护——这是操作系统所做的为数不多的事情之一(而且,如果文件可以读取,加密也可以被破解)
    • 易于设置开发/测试环境-只需打开开发/测试的权限。此外,只有生产运行时服务器需要具有适当的安全性
    • 避免依赖“无业务价值”库(这无助于解决您的业务问题)
  6. # 6 楼答案

    通常情况下,应用程序只需使用一个用户名就可以对sql数据库进行身份验证,必要时将用户的详细信息作为查询中的数据传递给sql数据库,以便您只返回与该最终用户相关的数据。您的客户端是否已指定每个最终用户都应作为单独的用户对数据库进行身份验证