前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >spring boot 加密_springboot 密码加密

spring boot 加密_springboot 密码加密

作者头像
全栈程序员站长
发布于 2022-11-09 07:11:20
发布于 2022-11-09 07:11:20
2.8K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。


首先介绍一下jasypt的使用方法

可以参考下面这篇文章:

Get史上最优雅的加密方式!没有之一!

版本对应的坑

使用的时候还是遇到一个坑,就是jasypt的版本与spring boot版本存在对应情况。可以看到jasypt是区分java7和java8的,也存在依赖spring版本的情况。

自己尝试了一下

在使用jasypt-spring-boot-starter的前提下

jasypt版本

springboot版本

2.1.0

2.1.0

1.5

1.4.2

1.5

1.5.3

1.8

1.4.2

所以如果引入maven之后启动系统报错,那么可以根据版本对应情况这个角度进行排查。

关键技术点

下面说一下jasypt的两个关键的技术实现点

一是如何实现对spring环境中包含的PropertySource对象实现加密感知的

二是其默认的PBEWITHMD5ANDDES算法是如何工作的,并澄清一下在使用jasypt的时候最常遇到的一个疑问:既然你的password也配置在properties文件中,那么我拿到了加密的密文和password,不是可以直接解密吗?

源码解析

总结来说:其通过BeanFactoryPostProcessor#postProcessBeanFactory方法,获取所有的propertySource对象,将所有propertySource都会重新包装成新的EncryptablePropertySourceWrapper

解密的时候,也是使用EncryptablePropertySourceWrapper#getProperty方法,如果通过 prefixes/suffixes 包裹的属性,那么返回解密后的值;如果没有被包裹,那么返回原生的值。从源头开始走起:

将jar包引入到spring boot中

spring.factories

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ulisesbocchio.jasyptspringboot.JasyptSpringBootAutoConfiguration

这里补充一下spring boot @EnableAutoConfiguration的原理。

@EnableAutoConfiguration原理

@EnableAutoConfiguration注解@Import(AutoConfigurationImportSelector.class)

这个配置类实现了ImportSelector接口,重写其selectImports方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List<String> configurations = getCandidateConfigurations(annotationMetadata,
      attributes);

getCandidateConfigurations方法,会从classpath中搜索所有META-INF/spring.factories配置文件,然后,将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration key对应的配置项加载到spring容器中。这样就实现了在spring boot中加载外部项目的bean或者第三方jar中的bean。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
      AnnotationAttributes attributes) {
   List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
         getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
   Assert.notEmpty(configurations,
         "No auto configuration classes found in META-INF/spring.factories. If you "
               + "are using a custom packaging, make sure that file is correct.");
   return configurations;
}

其内部实现的关键点有:

1. ImportSelector 该接口的方法的返回值都会被纳入到spring容器的管理中

2. SpringFactoriesLoader 该类可以从classpath中搜索所有META-INF/spring.factories配置文件,读取配置

@EnableAutoConfiguration注解中有spring.boot.enableautoconfiguration=true就开启,默认为true,可以在application.properties中设置此开关项

exclude()方法是根据类排除,excludeName是根据类名排除

在spring-boot-autoconfigure jar中,META-INF中有一个spring.factories文件,其中配置了spring-boot所有的自动配置参数,如GsonAutoConfiguration,配合@ConditionalOnClass(Gson.class),可以实现如果Gson bean存在,就启动自动注入,否则就不启用此注入的灵活配置

好了,有了上面的基础知识,我们就关心JasyptSpringBootAutoConfiguration

JasyptSpringBootAutoConfiguration

其@Import EnableEncryptablePropertySourcesConfiguration

关注两个地方

一是其@Import的StringEncryptorConfiguration.class

如果没有自定义的EncryptorBean,即jasyptStringEncryptor bean,那么就注册默认的jasyptStringEncryptor bean

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Conditional(OnMissingEncryptorBean.class)
@Bean(name = ENCRYPTOR_BEAN_PLACEHOLDER)
public StringEncryptor stringEncryptor(Environment environment) {
    String encryptorBeanName = environment.resolveRequiredPlaceholders(ENCRYPTOR_BEAN_PLACEHOLDER);
    LOG.info("String Encryptor custom Bean not found with name '{}'. Initializing String Encryptor based on properties with name '{}'",
             encryptorBeanName, encryptorBeanName);
    return new LazyStringEncryptor(() -> {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(getRequiredProperty(environment, "jasypt.encryptor.password"));
        config.setAlgorithm(getProperty(environment, "jasypt.encryptor.algorithm", "PBEWithMD5AndDES"));
        config.setKeyObtentionIterations(getProperty(environment, "jasypt.encryptor.keyObtentionIterations", "1000"));
        config.setPoolSize(getProperty(environment, "jasypt.encryptor.poolSize", "1"));
        config.setProviderName(getProperty(environment, "jasypt.encryptor.providerName", "SunJCE"));
        config.setSaltGeneratorClassName(getProperty(environment, "jasypt.encryptor.saltGeneratorClassname", "org.jasypt.salt.RandomSaltGenerator"));
        config.setStringOutputType(getProperty(environment, "jasypt.encryptor.stringOutputType", "base64"));
        encryptor.setConfig(config);
        return encryptor;
    });
}

StringEncryptor接口提供了加密和解密的方法

我们可以自定义StringEncryptor,如

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class JasyptConfig {

    @Bean(name = "jasypt.encryptor.bean:jasyptStringEncryptor")
    public StringEncryptor stringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword("password");
        config.setAlgorithm("PBEWithMD5AndDES");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        return encryptor;
    }
}

二是其对spring环境中包含的PropertySource对象的处理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
@Import(StringEncryptorConfiguration.class)
public class EnableEncryptablePropertySourcesConfiguration implements EnvironmentAware {

    private static final Logger LOG = LoggerFactory.getLogger(EnableEncryptablePropertySourcesConfiguration.class);
    private ConfigurableEnvironment environment;

    @Bean
    public EnableEncryptablePropertySourcesPostProcessor enableEncryptablePropertySourcesPostProcessor() {
        boolean proxyPropertySources = environment.getProperty("jasypt.encryptor.proxyPropertySources", Boolean.TYPE, false);
        InterceptionMode interceptionMode = proxyPropertySources ? InterceptionMode.PROXY : InterceptionMode.WRAPPER;
        return new EnableEncryptablePropertySourcesPostProcessor(environment, interceptionMode);
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = (ConfigurableEnvironment) environment;
    }
}

其提供了两种模式来创建 分别为proxy和wrapper 默认情况下interceptionMode为wrapper

下面就是关键了,new了一个EnableEncryptablePropertySourcesPostProcessor

其implements BeanFactoryPostProcessor

这里又需要两个背景知识

一是AbstractApplicationContext的refresh方法

是启动spring容器的关键方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

来注册我们下面的postProcessors

二是BeanFactoryPostProcessor接口的作用

BeanFactoryPostProcessor接口提供了postProcessBeanFactory方法,在容器初始化之后执行一次

invokeBeanFactoryPostProcessors,获取的手动注册的BeanFactoryPostProcessor

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Invoke the given BeanFactoryPostProcessor beans.
 */
private static void invokeBeanFactoryPostProcessors(
      Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

   for (BeanFactoryPostProcessor postProcessor : postProcessors) {
      postProcessor.postProcessBeanFactory(beanFactory);
   }
}

可以看到postProcessors有4个

接下来看关键的EnableEncryptablePropertySourcesPostProcessor

EnableEncryptablePropertySourcesPostProcessor

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class EnableEncryptablePropertySourcesPostProcessor implements BeanFactoryPostProcessor, ApplicationListener<ApplicationEvent>, Ordered {

其实现了BeanFactoryPostProcessor以及Ordered接口

其中getOrder方法 让这个jasypt定义的BeanFactoryPostProcessor的初始化顺序最低,即最后初始化

我们知道spring中排序分为两种PriorityOrdered 和Ordered接口,一般来说就是PriorityOrdered 优于Ordered 其次都是按照order大小来的排序

我们就知道了接下来就执行EnableEncryptablePropertySourcesPostProcessor的postProcessBeanFactory方法,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    LOG.info("Post-processing PropertySource instances");
    MutablePropertySources propSources = environment.getPropertySources();
    StreamSupport.stream(propSources.spliterator(), false)
        .filter(ps -> !(ps instanceof EncryptablePropertySource))
        .map(s -> makeEncryptable(s, beanFactory))
        .collect(toList())
        .forEach(ps -> propSources.replace(ps.getName(), ps));
}

接下来,获取所有的propertySource对象

然后用stream方式遍历,如果是通过jasypt加密的,那么来执行方法makeEncryptable,使得propertySource对象具备加密解密的能力

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private <T> PropertySource<T> makeEncryptable(PropertySource<T> propertySource, ConfigurableListableBeanFactory registry) {
    StringEncryptor encryptor = registry.getBean(environment.resolveRequiredPlaceholders(ENCRYPTOR_BEAN_PLACEHOLDER), StringEncryptor.class);
    PropertySource<T> encryptablePropertySource = interceptionMode == InterceptionMode.PROXY
            ? proxyPropertySource(propertySource, encryptor) : instantiatePropertySource(propertySource, encryptor);
    LOG.info("Converting PropertySource {} [{}] to {}", propertySource.getName(), propertySource.getClass().getName(),
             AopUtils.isAopProxy(encryptablePropertySource) ? "AOP Proxy" : encryptablePropertySource.getClass().getSimpleName());
    return encryptablePropertySource;
}

首先获取StringEncrypt Bean,然后执行instantiatePropertySource方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private <T> PropertySource<T> instantiatePropertySource(PropertySource<T> propertySource, StringEncryptor encryptor) {
    PropertySource<T> encryptablePropertySource;
    if (propertySource instanceof MapPropertySource) {
        encryptablePropertySource = (PropertySource<T>) new EncryptableMapPropertySourceWrapper((MapPropertySource) propertySource, encryptor);
    } else if (propertySource.getClass().getName().equals("org.springframework.boot.context.config.ConfigFileApplicationListener$ConfigurationPropertySources")) {
        //Some Spring Boot code actually casts property sources to this specific type so must be proxied.
        encryptablePropertySource = proxyPropertySource(propertySource, encryptor);
    } else if (propertySource instanceof EnumerablePropertySource) {
        encryptablePropertySource = new EncryptableEnumerablePropertySourceWrapper<>((EnumerablePropertySource) propertySource, encryptor);
    } else {
        encryptablePropertySource = new EncryptablePropertySourceWrapper<>(propertySource, encryptor);
    }
    return encryptablePropertySource;
}

可以看到将所有propertySource都会重新包装成新的EncryptablePropertySourceWrapper

log日志:将上面的6个对象包装一下

最后的application.properties中的配置项结果

完整的转换完成后的EncryptablePropertySourceWrapper

到这里就注册postProcessor完成了,而且每个PropertySource warpped,具备了加密解密的能力,然后继续回到AbstractApplicationContext的流程

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

具体的解密过程

当spring boot项目启动的时候,需要用到属性值的时候,就是将原本spring中的propertySource的getProperty()方法委托给其自定义的实现EncryptablePropertySourceWrapper,调用其getProperty()方法,在这个方法的自定义实现中。判断是否是已经加密的value,如果是,则进行解密。如果不是,那就返回原值。

调用EncryptablePropertySourceWrapper的getProperty方法,其extends PropertySource,override了getProperty方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class EncryptablePropertySourceWrapper<T> extends PropertySource<T> implements EncryptablePropertySource<T> {
    private final PropertySource<T> delegate;
    private final StringEncryptor encryptor;

    public EncryptablePropertySourceWrapper(PropertySource<T> delegate, StringEncryptor encryptor) {
        super(delegate.getName(), delegate.getSource());
        Assert.notNull(delegate, "PropertySource delegate cannot be null");
        Assert.notNull(encryptor, "StringEncryptor cannot be null");
        this.delegate = delegate;
        this.encryptor = encryptor;
    }

    @Override
    public Object getProperty(String name) {
        return getProperty(encryptor, delegate, name);
    }
}

其getProperty就去调用其implements的EncryptablePropertySource的getProperty方法,于是执行下面

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface EncryptablePropertySource<T> {
    public default Object getProperty(StringEncryptor encryptor, PropertySource<T> source, String name) {
        Object value = source.getProperty(name);
        if(value instanceof String) {
            String stringValue = String.valueOf(value);
            if(PropertyValueEncryptionUtils.isEncryptedValue(stringValue)) {
                value = PropertyValueEncryptionUtils.decrypt(stringValue, encryptor);
            }
        }
        return value;
    }
}

isEncryptedValue方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static final String ENCRYPTED_VALUE_PREFIX = "ENC(";
private static final String ENCRYPTED_VALUE_SUFFIX = ")";

public static boolean isEncryptedValue(final String value) {
    if (value == null) {
        return false;
    }
    final String trimmedValue = value.trim();
    return (trimmedValue.startsWith(ENCRYPTED_VALUE_PREFIX) && 
            trimmedValue.endsWith(ENCRYPTED_VALUE_SUFFIX));
}

如果通过 prefixes/suffixes 包裹的属性,那么返回解密后的值;

如果没有被包裹,那么返回原生的值;

如果是加密的值,那么就去解密

StandardPBEByteEncryptor

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public byte[] decrypt(final byte[] encryptedMessage) 
throws EncryptionOperationNotPossibleException {
if (encryptedMessage == null) {
return null;
}
// Check initialization
if (!isInitialized()) {
initialize();
}
if (this.saltGenerator.includePlainSaltInEncryptionResults()) {
// Check that the received message is bigger than the salt
if (encryptedMessage.length <= this.saltSizeBytes) {
throw new EncryptionOperationNotPossibleException();
}
}
try {
// If we are using a salt generator which specifies the salt
// to be included into the encrypted message itself, get it from 
// there. If not, the salt is supposed to be fixed and thus the
// salt generator can be safely asked for it again.
byte[] salt = null; 
byte[] encryptedMessageKernel = null; 
if (this.saltGenerator.includePlainSaltInEncryptionResults()) {
final int saltStart = 0;
final int saltSize = 
(this.saltSizeBytes < encryptedMessage.length? this.saltSizeBytes : encryptedMessage.length);
final int encMesKernelStart =
(this.saltSizeBytes < encryptedMessage.length? this.saltSizeBytes : encryptedMessage.length);
final int encMesKernelSize = 
(this.saltSizeBytes < encryptedMessage.length? (encryptedMessage.length - this.saltSizeBytes) : 0);
salt = new byte[saltSize];
encryptedMessageKernel = new byte[encMesKernelSize];
System.arraycopy(encryptedMessage, saltStart, salt, 0, saltSize);
System.arraycopy(encryptedMessage, encMesKernelStart, encryptedMessageKernel, 0, encMesKernelSize);
} else if (!this.usingFixedSalt){
salt = this.saltGenerator.generateSalt(this.saltSizeBytes);
encryptedMessageKernel = encryptedMessage;
} else {
// this.usingFixedSalt == true
salt = this.fixedSaltInUse;
encryptedMessageKernel = encryptedMessage;
}
final byte[] decryptedMessage;
if (this.usingFixedSalt) {
/*
* Fixed salt is being used, therefore no initialization supposedly needed
*/
synchronized (this.decryptCipher) {
decryptedMessage = 
this.decryptCipher.doFinal(encryptedMessageKernel);
}
} else {
/*
* Perform decryption using the Cipher
*/
final PBEParameterSpec parameterSpec = 
new PBEParameterSpec(salt, this.keyObtentionIterations);
synchronized (this.decryptCipher) {
this.decryptCipher.init(
Cipher.DECRYPT_MODE, this.key, parameterSpec);
decryptedMessage = 
this.decryptCipher.doFinal(encryptedMessageKernel);
}
}
// Return the results
return decryptedMessage;
} catch (final InvalidKeyException e) {
// The problem could be not having the unlimited strength policies
// installed, so better give a usefull error message.
handleInvalidKeyException(e);
throw new EncryptionOperationNotPossibleException();
} catch (final Exception e) {
// If decryption fails, it is more secure not to return any 
// information about the cause in nested exceptions. Simply fail.
throw new EncryptionOperationNotPossibleException();
}
}

以spring.datasource.username为例:

明文是root

密文是ENC(X4OZ4csEAWqPCEvWf+aRPA==)

可以看到其salt是encryptedMessage的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
System.arraycopy(encryptedMessage, saltStart, salt, 0, saltSize);
System.arraycopy(encryptedMessage, encMesKernelStart, encryptedMessageKernel, 0, encMesKernelSize);

0-7byte解析为salt,8-15byte解析为密文

然后就通过基本的PBE解析方式,来解析出来

ASCII码对应的结果就是root

PBE解析原理图:

加密过程:每一次随机产生新的salt,所以每一次加密后生成的密文是不同的

解密过程:

所以我们就可以知道,如果我获得了jasypt的password,那么由于其salt是放在encryptedMessage中的,那么我是没什么压力就可以解密的。

所以应该java -jar –Djasypt.encryptor.password=xxx abc.jar方式来启动服务。这样只要在运维端不泄露password,那么只拿到配置文件的密文,还是安全的。

补充1:查看JDK提供的Cipher算法

jasypt默认使用的是PBEWITHMD5ANDDES,其实JDK中由SunJCE所提供的。

可以通过下面的代码来查看JDK中提供了哪些Cipher算法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void listJdkAlgorithm() {
/*        Provider[] providers = Security.getProviders();
for (Provider provider :
providers) {
LOGGER.info("security provider: {} , version: {}", provider.getName(), provider.getVersion());
LOGGER.info("security provider info: {}", provider.getInfo());
}*/
Set<String> messageDigest = Security.getAlgorithms("Cipher");
for (String s :
messageDigest) {
LOGGER.info("MessageDigest: {}",s);
}
}

更全面的安全方面的算法,如摘要算法、签名算法等,参考:

Standard Algorithm Name Documentation

补充2:PBE的基础算法demo,

而且可以看出来,jasypt中使用了几乎相同的代码来进行加解密的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class PBECipher {
static final String CIPHER_NAME = "PBEwithMD5AndDES";
public static byte[] encrypt(String password, byte[] salt, byte[] input) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(CIPHER_NAME);
// 这个secretKey 就是我们将来要使用的加密的密钥
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
// 传入1000,表示用户输入的口令,会与这个salt进行1000次的循环
PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 1000);
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, pbeParameterSpec);
return cipher.doFinal(input);
}
public static byte[] decrypt(String password, byte[] salt, byte[] input) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(CIPHER_NAME);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 1000);
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
cipher.init(Cipher.DECRYPT_MODE, secretKey, pbeParameterSpec);
return cipher.doFinal(input);
}
}

测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testPBE() throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException {
String message = "constfafa";
String password = "ydbs";
byte[] salt = SecureRandom.getInstanceStrong().generateSeed(8);
System.out.printf("salt: %032x\n", new BigInteger(1, salt));
//加密和解密的salt是一样的
byte[] data = message.getBytes("UTF-8");
byte[] encrypt = PBECipher.encrypt(password, salt, data);
LOGGER.info("encrypted data: {}", Base64.getEncoder().encodeToString(encrypt));
byte[] decrypt = PBECipher.decrypt(password, salt, encrypt);
LOGGER.info("decrypted data: {}", new String(decrypt,"UTF-8"));
}

参考:

Jasypt之源码解析

官方github

8.Java 加解密技术系列之 PBE – crazyYong – 博客园

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月26日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
jasypt 原理_litmp试剂
引入了jasypt-spring-boot-starter的jar包之后,项目启动的时候,是如何加载jasypt的呢? 这利用的是项目启动类上的一个注解@SpringBootApplication,这个注解中引用了@EnableAutoConfiguration注解。
全栈程序员站长
2022/11/09
5080
jasypt 原理_litmp试剂
如何优雅的加密配置文件中的敏感信息
我们平时的项目中,会在配置文件中配置一些敏感信息,比如配置数据库账号、密码等信息。如果我们将配置文件与代码一起打包,别人拿到jar包后很有可能反编译jar,从而获取里面的配置文件信息。如果有人对数据库信息恶意破坏,那么就会产生不可估量的损失。
Lvshen
2022/05/05
3K0
如何优雅的加密配置文件中的敏感信息
如何给application.yml文件的敏感信息加密?
我的Demo里使用的是SpringBoot3.0之后的版本,所以大家如果像我一样都是基于SpringBoot3.0之后的,jasypt一定要使用3.0.5以后的版本。
每周聚焦
2024/05/25
2130
如何给application.yml文件的敏感信息加密?
Springboot 配置文件、隐私数据脱敏的最佳实践(原理+源码)
这几天公司在排查内部数据账号泄漏,原因是发现某些实习生小可爱居然连带着账号、密码将源码私传到GitHub上,导致核心数据外漏,孩子还是没挨过社会毒打,这种事的后果可大可小。
程序员小富
2021/08/03
9350
jasypt对配置文件加密
这里可以看到,redis和mariadb相同的密码,其密文是不一致的。而且配置文件中不需要任何jasypt的配置。程序可以正常启动并解密。
奇门水镜
2024/04/15
5300
Spring Boot 保护敏感配置的 4 种方法,让你的系统不再裸奔!!
点击关注公众号,Java干货及时送达 0、问题背景 用 Spring Boot 框架的小伙伴应该都知道,Spring Boot 有个主要的 applicaiton 配置文件,那就会涉及到敏感配置信息,比如各种中间件的连接用户名密码信息、以及各种第三方的 KEY、密钥等。 这种敏感信息如果直接放在配置文件中肯定是不安全的,甚至在很多行业及领域(比如:支付领域)都是不合规的,所以需要保护 Spring Boot 中的敏感配置信息。 所以,你还在让你的 Spring Boot 系统裸奔吗?如果是,那不妨看看本文
Java技术栈
2022/03/14
1.3K0
Springboot 配置文件、隐私数据脱敏的最佳实践(原理+源码)
这几天公司在排查内部数据账号泄漏,原因是发现某些实习生小可爱居然连带着账号、密码将源码私传到GitHub上,导致核心数据外漏,孩子还是没挨过社会毒打,这种事的后果可大可小。
程序员小富
2021/08/06
6960
Springboot 配置文件、隐私数据脱敏的最佳实践(原理+源码)
[Spring Boot] 如何优雅的对配置文件进行加密
Jasypt Spring Boot为Spring Boot Applications中的属性源提供加密支持。 有三种方法可以集成jasypt-spring-boot到您的项目中:
架构探险之道
2019/08/06
8.3K0
jasypt加密配置文件_jenkins api
1、Jasypt Spring Boot 为 spring boot 应用程序中的属性源提供加密支持,出于安全考虑,Spring boot 配置文件中的敏感信息通常需要对它进行加密/脱敏处理,尽量不使用明文,要实现这一点,办法有很多,自己手动对敏感信息进行加解密也是可以的。
全栈程序员站长
2022/11/09
1.7K0
jasypt加密配置文件_jenkins api
springboot 之 使用jasypt加密解密插件[通俗易懂]
如果需要使用自定义的加减密方法,我们只需要实现StringEncryptor接口即可,具体如下:
全栈程序员站长
2022/11/09
3.6K0
springboot 之 使用jasypt加密解密插件[通俗易懂]
springboot 集成mybatis-plus_Spring Boot
将生成的加密密匙配置在配置文件中即可,ENC 是约定的关键字,在启动时会解析所有 PropertySource 中的加密属性。 4.1 这里更改yml配置中连接数据库的密码
全栈程序员站长
2022/11/09
3620
springboot 集成mybatis-plus_Spring Boot
spring和springboot中加密连接数据库的信息前言:一、spring中加密连接数据库的信息:二、springboot项目中加密数据库连接信息:总结:
在实际开发中,一些关键的信息肯定是要加密的,否则就太不安全了。比如连接数据库的用户名和密码,一般就需要加密。接下来就看看spring项目和spring boot项目中分别是如何加密这些信息的。
贪挽懒月
2018/08/02
1.5K0
spring和springboot中加密连接数据库的信息前言:一、spring中加密连接数据库的信息:二、springboot项目中加密数据库连接信息:总结:
聊聊springboot项目数据库密码如何加密
在我们日常开发中,我们可能很随意把数据库密码直接明文暴露在配置文件中,在开发环境可以这么做,但是在生产环境,是相当不建议这么做,毕竟安全无小事,谁也不知道哪天密码就莫名其妙泄露了。今天就来聊聊在springboot项目中如何对数据库密码进行加密
lyb-geek
2021/07/06
2.1K0
聊聊springboot项目数据库密码如何加密
一文读懂Spring Environment
如今,致力于帮助开发者用更少的代码、更快地写出生产级系统的 Spring Boot 已然成为 Java 应用开发的事实标准。在 Spring Boot 提供的众多特性中,自动配置无疑是对提升开发体验最显著的一个特性,Spring Boot 基于这一特性为开发人员自动声明了若干开箱即用、具备某一功能的 Bean。大多数情况下,自动配置的 Bean 刚好能满足大家的需求,但在某些情况下,不得不完整地覆盖它们,这个时候只需要重新声明相关类型的 Bean 即可,因为绝大多数自动配置的 Bean 都会由@ConditionalOnMissingBean注解修饰。幸运的是,如果只是想微调一些细节,比如改改端口号 (server.port) 和数据源 URL (spring.datasource.url) ,那压根没必要重新声明ServerProperties和DataSourceProperties这俩 Bean 来覆盖自动配置的 Bean。Spring Boot 为自动配置的 Bean 提供了1000多个用于微调的属性,当需要调整设置时,只需要在环境变量、命令行参数或配置文件 (application.properties/application.yml) 中进行指定即可,这就是 Spring Boot 的Externalized Configuration (配置外化) 特性。
程序猿杜小头
2022/12/01
1.1K0
一文读懂Spring Environment
天呐,你生产环境中的密码还在裸奔吗?
这是节选自某个典型的 Spring Boot 项目的 application.yml 配置文件。
create17
2021/01/04
1.3K0
天呐,你生产环境中的密码还在裸奔吗?
Spring拓展接口之BeanFactoryPostProcessor,占位符与敏感信息解密原理
  简单来说,BeanFactoryPostProcessor是spring对外提供的接口,用来拓展spring,能够在spring容器加载了所有bean的信息信息之后、bean实例化之前执行,修改bean的定义属性;有人可能会问,这有什么用?大家还记得spring配置文件中的占位符吗? 我们会在spring配置中配置PropertyPlaceholderConfigurer(继承PropertyResourceConfigurer)bean来处理占位符, 举个例子大家就有印象了
青石路
2019/04/09
1.3K0
Spring拓展接口之BeanFactoryPostProcessor,占位符与敏感信息解密原理
SpringBoot中的配置文件信息加密
在SpringBoot项目中,有的配置文件信息比较敏感,比如数据库的密码信息等,直接以明文的形式写在配置文件中或许并不安全.
玖柒的小窝
2021/12/14
1.6K0
SpringBoot中的配置文件信息加密
解决springboot yml文件明文显示密码的问题
用户9131103
2023/07/17
1.1K0
数据库密码配置项都不加密?心也太大了!
这是节选自某个典型的Spring Boot项目的application.properties配置文件。
好好学java
2020/05/27
1.5K0
数据库密码配置项都不加密?心也太大了!
Springboot 配置文件脱敏的实践
数据安全这块还是挺严重的,尤其是自己专注于业务开发,不能总停留在一个地方,还要关注其他的一些问题,比如数据安全。
CBeann
2023/12/25
3250
Springboot 配置文件脱敏的实践
推荐阅读
相关推荐
jasypt 原理_litmp试剂
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文