Tomcat 配置文件数据库密码加密

几年前研究过Tomcat context.xml 中数据库密码改为密文的内容,因为当时在客户云桌面代码没有留备份也没有文章记录,最近项目又提出了这个需求就又重新拾起来学习一下。在网上找了一些资料,自己也大概试了一下,目前功能是实现了。

参考链接:

https://blog.csdn.net/fzzsh/article/details/8863338

https://blog.csdn.net/T_P_F/article/details/118552417

Tomcat 常见情况

正常的tomcat context.xml配置文件数据库用户名和密码都是明文的

<Resource name="jdbc/DSamdb" auth="Container" type="javax.sql.DataSource" description="test DB"
        initialSize="10" 
        maxWaitMillis="10000" maxTotal="80" maxIdle="20" minIdle="10" validationQuery="select 1"
        username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://localhost:3306/webtest?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT%2B8&amp;useSSL=false"         
   />

现在因为安全要求或者国家等保要求,这个数据库密码是需要加密的,并且要定期修改的,首先实现加密功能

Tomcat context.xml密码加密

tomcat加密是通过在配置文件中增加 factory参数让数据源的解析指到定制化的jar包中,对密码或用户名进行解析,加密后的配置文件信息

<Resource name="jdbc/DSamdb" auth="Container" type="javax.sql.DataSource" description="test DB"
        initialSize="10" 
        maxWaitMillis="10000" 
        maxTotal="80" maxIdle="20" minIdle="10" validationQuery="select 1"
        factory="com.axb.data.factory.DataSourceFactory"
        username="root"
        password="726f6f74" 
        driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://localhost:3306/webtest?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT%2B8&amp;useSSL=false"         
   />

factory="com.axb.data.factory.DataSourceFactory" 是包名+类名。password 的root已经加密为“726f6f74”,从网上找到加密算法比较简单,所以加密串看着也挺简单。

配置信息啰嗦完了,上代码:

DataSourceFactory.java 继承BasicDataSourceFactory

package com.axb.data.factory;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.sql.DataSource;
import net.sf.json.JSONObject;
import org.apache.tomcat.dbcp.dbcp.BasicDataSource;
import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;
import com.axb.data.factory.util.Encode;
import com.axb.data.factory.util.HttpUtil;

public class DataSourceFactory extends BasicDataSourceFactory {

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
            Hashtable environment) throws Exception {

        if (obj instanceof Reference) {
            //用户名没有加密
//            setUsername((Reference) obj);
            setPassword((Reference) obj);
        }
        return super.getObjectInstance(obj, name, nameCtx, environment);
        
    }

    private void setUsername(Reference ref) throws Exception {
        findDecryptAndReplace("username", ref);
    }

    private void setPassword(Reference ref) throws Exception {
        findDecryptAndReplace("password", ref);
    }

    private void findDecryptAndReplace(String refType, Reference ref)
            throws Exception {
        int idx = find(refType, ref);
        System.out.println(idx +"----->findDecryptAndReplace---" +ref.get(idx));

        String decodeStr = ref.get(idx).getContent().toString();
        System.out.println("findDecryptAndReplace---" +decodeStr);
        String decrypted = Encode.decode(decodeStr);
        
        replace(idx, refType, decrypted, ref);
       
    }

    private int find(String addrType, Reference ref) throws Exception {
        Enumeration enu = ref.getAll();
        for (int i = 0; enu.hasMoreElements(); i++) {
            RefAddr addr = (RefAddr) enu.nextElement();
            if (addr.getType().compareTo(addrType) == 0) {
                return i;
            }
        }
        throw new Exception("The \"" + addrType
                + "\" name/value pair was not found"
                + " in the Reference object. The reference Object is" + " "
                + ref.toString());
    }

    private void replace(int idx, String refType, String newValue, Reference ref)
            throws Exception {
        ref.remove(idx);
        ref.add(idx, new StringRefAddr(refType, newValue));
    }
   }

加密类,可使用自己的加密算法,主要修改encode和decode两个方法,自己可以写个main方法测试加解密功能。代码也是从CSDN找的,连接:

package com.axb.data.factory.util;

public class Encode {
    //加密
        public static String encode(String password) {

            String result = "";

            byte[] psd = password.getBytes();

            for (int i = 0; i < psd.length; i++) {

                result += Integer.toHexString(psd[i] & 0xff);
            }
            return result;
        }
        //解密
        public static String decode(String password) {

            String result = "";
            System.out.println("encode---->" +password);
            password = password.toUpperCase();
            int length = password.length() / 2;
            char[] hexChars = password.toCharArray();
            byte[] d = new byte[length];
            for (int i = 0; i < length; i++) {
                int pos = i * 2;
                d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
            }
            result = new String(d);
            return result;
        }

        //字符转字节
        public static byte charToByte(char c) {  
            return (byte) "0123456789ABCDEF".indexOf(c);  
        }

tomcat启动后控制台输出效果:

能正常启动就可以,该方法不需要额外的jar包,开发的时候只需要引入tomcat-dbcp.jar,这个包在tomcat的lib下就有。不需要额外下载。

通过http请求密码

这样改完以后配置文件密码是密文了,但是每次更换密码还是需要修改密文并重启tomcat,当然也可以把密码写在某个路径下的文件中。运维人员每次变更密码都要改,服务器多了也是需要花费不少时间。我就试着用http请求获取密码,改动是在findDecryptAndReplace 方法

private void findDecryptAndReplace(String refType, Reference ref)
            throws Exception {
        int idx = find(refType, ref);
        System.out.println(idx +"----->findDecryptAndReplace---" +ref.get(idx));

        String decodeStr = ref.get(idx).getContent().toString();
        System.out.println("findDecryptAndReplace---" +decodeStr);
        String decrypted = Encode.decode(decodeStr);
        
//        replace(idx, refType, decrypted, ref);
        
        /**
         * 试试远程获取密码
         */
        String url = "http://localhost:9002/getDataBaseInfo";
        String jsonData = "{\"userId\":\"zhangsan\"}";
        String returnStr  = HttpUtil.httpPost(url,jsonData);
        JSONObject tokenJSON = JSONObject.fromObject(returnStr);
        System.out.println("decrypted:==="+decrypted +"json_password"+tokenJSON.get("password"));
        System.out.println(tokenJSON.get("password")+"===="+tokenJSON.get("userName"));
        replace(idx, refType, tokenJSON.get("password").toString(), ref);
       
    }

启动后控制台日志:

http请求需要多引入一些jar包:

jar包直接扔到tomcat的lib目录下就可以。

测试方法类也简单

@RequestMapping(value = "/getDataBaseInfo", method = RequestMethod.POST)
    public String getDataBaseInfo(@RequestBody String josnString) {
        System.out.println("=================josnString="+josnString);
        Map m = new HashMap();
        m.put("userName","root");
        m.put("password","root");
        Gson gson = new Gson();
        gson.toJson(m);
        return gson.toJson(m);
    }

这种方式可以请求少修改配置文件,但还是需要重启服务器的,因为我试着修改密码为错误密码,应用还是能正常访问的。

代码链接:

https://download.csdn.net/download/jiudihanbing/87537958

没积分也可以直接粘贴文章中代码,有积分可以下载代码直接使用,测试代码因为很简单就没有了

上面的方法都不能让运维人员省时省力的解决问题,只是稍微合规和减小点工作量。

我公司有特权账号的产品可以让Tomact context.xml配置文件通过接口获取最新DB密码,同时也不需要重启tomcat,我以后有机会在了解一下实现机制。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Tomcat是一个流行的开源Java Web服务器,它被广泛用于部署和运行Java Web应用程序。它是Apache软件基金会的一个项目,提供了一个可扩展的、稳定的、高性能的Web容器,用于处理Java Servlet和JavaServer Pages(JSP)。 Tomcat的主要功能包括: 1. Servlet容器:Tomcat是一个Java Servlet容器,它可以运行基于Servlet规范的Java Web应用程序。它通过解析和执行Servlet代码,处理HTTP请求和响应,并提供了一组API来处理会话管理、请求调度等功能。 2. JSP引擎:Tomcat还包含一个JSP引擎,可以编译和执行JSP页面。JSP是一种动态生成HTML内容的技术,它允许在页面中嵌入Java代码,并根据请求动态生成内容。 3. 静态资源托管:Tomcat可以托管静态HTML、CSS、JavaScript等文件,使其可以通过HTTP访问。这使得Tomcat不仅适用于Java Web应用程序,也可以用作简单的静态文件服务器。 4. 连接池管理:Tomcat提供了连接池管理功能,可以在应用程序和数据库之间建立并管理连接池。这样可以提高数据库访问的性能和效率。 5. 安全性支持:Tomcat支持SSL/TLS加密通信和基于角色的访问控制,可以保护Web应用程序的安全性。 Tomcat的架构相对简单,易于使用和配置。它可以作为独立的Web服务器运行,也可以与其他前端服务器(例如Apache HTTP Server)配合使用,以提供更高的性能和可靠性。 总的来说,Tomcat是一个功能强大且易于使用的Java Web服务器,适用于部署和运行各种Java Web应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值