gpt4 book ai didi

java - RESTful 客户端/服务器的 HTTPS 通信问题

转载 作者:太空宇宙 更新时间:2023-11-03 14:25:41 25 4
gpt4 key购买 nike

我正在尝试通过 HTTPS 在我编写的应用程序上设置基于 Web 的安全性,该应用程序使用 Spring Boot 来提供 RESTful 功能。该应用程序仅使用 HTTP 即可按预期工作。

我已经对我需要做什么来在应用程序中“启用”HTTPS 进行了大量研究(至少我是这么认为的),并将提供代码片段和配置来说明我所拥有的。

我认为我很接近,但它还没有奏效,我尝试过的各种方法都没有成功。

当前的实现不要求服务(服务器)验证客户端的凭据。此外,我不需要任何形式的“用户”身份验证。

这里是对当前设置的简要描述:

  • 一个“任务规划器”服务,它将对另外两个进行 REST 调用执行某些工作的服务。
  • “路线生成器”服务,当被任务规划者调用时,将返回一些数据作为响应。
  • “路线评估器”服务,当任务规划器调用该服务时,将返回一些数据以供响应。
  • “客户”这将向任务规划器发出 REST 调用以“规划任务”。任务规划器不返回任何内容。

还有一个“虚拟”服务,它只是将当前时间返回给来自客户端的 GET 请求。简单的测试器。

所有这五个元素都作为 @Service 实现,任务规划器、“路线”服务和虚拟对象都有相应的 Controller (@RestController),其中 REST 端点被映射。

我为三个服务(任务规划器和两个“路线”服务 - 虚拟机只使用其中一个“路线”证书)生成了证书,这些文件位于“ keystore ”位置。我还有一个“信任库”位置,其中包含生成 CA 的公钥。所有五个服务都有信任库。

我无法让客户端与任何服务对话(为简单起见,使用“虚拟”)。我还尝试通过 Web 浏览器访问虚拟端点,结果似乎表明通信管道的某些部分正在发生,但失败了。

下面是代码片段,希望能以代码方式显示图片。

服务器(以“虚拟”为例)

虚拟.java:

@Service
@Profile("dummy")
public class Dummy {
public String doIt() {
return Long.toString(System.currentTimeMillis());
}
}

虚拟 Controller .java:

@RestController
@RequestMapping("/rst")
@Profile("dummy")
public class DummyController {
@Autowired
private Dummy service;

@GetMapping(value = "/dummy", produces = "text/plain")
public String dummy() {
return service.doIt();
}
}

注意:下面的类和 application.yml 中的属性是我根据网络上的示例改编的 (https://github.com/indrabasak/spring-tls-example)。我不太理解已经定义的“角色”的概念。这里有很多我还是不明白。

安全配置.java:

@Configuration
@EnableWebSecurity
@EnableConfigurationProperties(SecurityAuthProperties.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final Logger logger = LogManager.getLogger();
private final SecurityAuthProperties properties;

@Autowired
public SecurityConfiguration(SecurityAuthProperties properties) {
this.properties = properties;
}

@Override
public void configure(AuthenticationManagerBuilder auth) {
// properties.getUsers().forEach((key, value) -> {
// try {
// auth.inMemoryAuthentication()
// .passwordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder())
// .withUser(value.getId()).password(value.getPassword()).roles(value.getRoles());
// logger.info("Added user " + value.getId() + " with password " + value.getPassword());
// } catch (Exception e) {
// throw new SecurityConfigurationException(
// "Problem encountered while setting up authentication mananger", e);
// }
// });
}

@Override
public void configure(HttpSecurity http) throws Exception {
properties.getEndpoints().forEach((key, value) -> {
try {
for (HttpMethod method : value.getMethods()) {
// http.authorizeRequests().antMatchers(method, value.getPath())
// .hasAnyAuthority(value.getRoles()).and().httpBasic().and().csrf().disable();
http.authorizeRequests().antMatchers(method, value.getPath()).permitAll().and()
.httpBasic().and().csrf().disable();
logger.info("Added security for path " + value.getPath() + " and method " + method);
}
} catch (Exception e) {
throw new SecurityConfigurationException(
"Problem encountered while setting up endpoint restrictions", e);
}
});

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

@Override
public void configure(WebSecurity web) {
// TODO - what (if anything) do we do here?
}
}

SecurityAuthProperties.java:(“用户”部分目前已禁用,因为我们未使用它。)

@ConfigurationProperties("security.auth")
public class SecurityAuthProperties {

private static final String ROLE_PREFIX = "ROLE_";
public static final String ROLE_ANONYMOUS = "ROLE_ANONYMOUS";
private Map<String, Endpoint> endpoints = new HashMap<>();
// private Map<String, User> users = new HashMap<>();

@PostConstruct
public void init() {
endpoints.forEach((key, value) -> {
List<String> roles = new ArrayList<>();
for (String role : value.getRoles()) {
roles.add(ROLE_PREFIX + role);
}
value.setRoles(roles.toArray(new String[0]));
});

// users.forEach((key, value) -> {
// if (value.getId() == null) {
// value.setId(key);
// }
//
// if (value.getEncoding() != null) {
// value.setPassword("{" + value.getEncoding().trim() + "}" + value.getPassword());
// } else {
// value.setPassword("{noop}" + value.getPassword());
// }
// });
}

public Map<String, Endpoint> getEndpoints() {
return endpoints;
}

public void setEndpoints(Map<String, Endpoint> endpoints) {
this.endpoints = endpoints;
}

// public Map<String, User> getUsers() {
// return users;
// }
//
// public void setUsers(Map<String, User> users) {
// this.users = users;
// }

public static class Endpoint {
private String path;
private HttpMethod[] methods;
private String[] roles;

// trivial getters/setters removed for brevity

public String[] getRoles() {
if (roles == null || roles.length == 0) {
roles = new String[1];
roles[0] = ROLE_ANONYMOUS;
}
return roles;
}
}

public static class User {
private String id;
private String encoding;
private String password;
private String[] roles;

// trivial getters/setters removed for brevity

public String[] getRoles() {
if (roles == null || roles.length == 0) {
roles = new String[1];
roles[0] = ROLE_ANONYMOUS;
}
return roles;
}
}
}

应用程序.yml:

...
server:
port: 8443
ssl:
enabled: true
protocol: TLS
trust-store-type: JKS
trust-store: classpath:truststore/server.truststore
trust-store-password: <password>
key-store-type: JKS

security:
auth:
endpoints:
endpoint1:
path: /rst/dummy
methods: GET
roles:

客户

客户端服务.java:

@Service
public class ClientService {
private final Logger logger = LogManager.getLogger();

private static final String REST_DUMMY = "rst/dummy";

// @Autowired
// private RestTemplate template;

@Value("${web.protocol:http}")
private String protocol;
@Value("${mission-planner.host:localhost}")
private String missionPlannerHost;
@Value("${mission-planner.port:8443}")
private int missionPlannerPort;

@Scheduled(fixedRate = 10000)
public void planMission() {
logger.info("ClientService.planMission()");
RestTemplate template = new RestTemplate();
String url = new URLBuilder.Builder().usingProtocol(protocol).onHost(missionPlannerHost)
.atPort(missionPlannerPort).atEndPoint(REST_DUMMY).build();
String response = template.getForObject(url, String.class);
}
}

我的一个大问题是,如果服务器不需要验证客户端,需要在客户端完成什么(如果有)“安全”配置?我确实有一堆类/配置试图在客户端执行此操作,但目前已禁用。

使用如图所示的代码,当我尝试与虚拟服务通信时,客户端出现异常:

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8443/rst/dummy": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

更新

我决定尝试将 server.ssl.key-alias(我在运行配置中通过 -D 设置)更改为大写(这是证书似乎具有的),现在得到一个新的有趣的异常(exception)。注意:我还为客户端和虚拟服务设置了 javax.net.debug=ssl

scheduling-1, WRITE: TLSv1.2 Handshake, length = 196
scheduling-1, READ: TLSv1.2 Alert, length = 2
scheduling-1, RECV TLSv1.2 ALERT: fatal, handshake_failure
scheduling-1, called closeSocket()
scheduling-1, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
[2019-08-09 13:28:45.648] scheduling-1 ERROR: support.TaskUtils$LoggingErrorHandler:96 - Unexpected error occurred in scheduled task.
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8443/rst/dummy": Received fatal alert: handshake_failure; nested exception is javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

这是我在服务上得到的:

matching alias: route_assessor_1
matching alias: route_assessor_1
qtp1060563153-39, fatal error: 40: no cipher suites in common
javax.net.ssl.SSLHandshakeException: no cipher suites in common
%% Invalidated: [Session-1, SSL_NULL_WITH_NULL_NULL]
qtp1060563153-39, SEND TLSv1.2 ALERT: fatal, description = handshake_failure
qtp1060563153-39, WRITE: TLSv1.2 Alert, length = 2
qtp1060563153-39, fatal: engine already closed. Rethrowing javax.net.ssl.SSLHandshakeException: no cipher suites in common
qtp1060563153-39, called closeOutbound()
qtp1060563153-39, closeOutboundInternal()

最佳答案

这似乎是 Activity 部件太多而忘记重新打开某些东西的情况。

经过相当多的挣扎并回到原始源代码 (https://github.com/indrabasak/spring-tls-example) 并试验了一段时间,我看不出作者的工作代码和我的非工作代码之间有任何显着差异。

然后其中一个突然出现的情况发生了,我意识到我没有在我的客户端中使用安全配置的 REST 模板(由于我现在不记得的原因它被注释掉了)。我只使用了一个普通的未配置模板。

我取消注释代码,你看,客户端现在验证服务器的证书。

下一个问题。

关于java - RESTful 客户端/服务器的 HTTPS 通信问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57433701/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com