Dzięki za odpowiedzi ;)
security by obscurity (prawie) nigdy nie jest dobrym rozwiązaniem.
Wymyślanie własnych rozwiązań związanych z bezpieczeństwem (prawie) nigdy nie jest dobrym rozwiązaniem,
Obliczanie hashy liczb mija się z celem, ponieważ bardzo łatwo jest po tej przestrzeni przeiterować, by odkryć pierwotną liczbę (cyfr jest wszak znacznie mniej niż np. drukowalnych znaków ASCII ;-))
Dokładnie jak mówisz, dlatego podałem możliwe rozwiązania problemu :D
@yarel
Dzięki za artykuł :). Chcę stworzyć proste REST API, w którym wystawiam REST resource, ale używam UUID na zewnątrz oraz ukrywam ID zasobów, żeby atakujący nie ich zgadł, na przykład tak dla testu:
Chcę po prostu korzystać z ID typu numerycznego SEQUENCE wewnątrz aplikacji, ale wystawiać już UUID na zewnątrz dla klientów, tak żeby zamaskować,i szukam na to fajnego rozwiązania, bez konieczności pisania dodatkowego zapytania jak to ma miejsce teraz, żeby znaleźć najpierw ID, muszę najpierw zrobić SELECT z UUID np. w UserFacade -> delete() albo update() gdybym chciał aktualizować rekord.
Przykładowo (Wiem, nakombinowane jest, dlatego chcę to wyprostować :) )
UserController
@RestController
@RequiredArgsConstructor
@RequestMapping("/users")
class UserController {
private final UserFacade userFacade;
@GetMapping(value = "/{uuid}")
ResponseEntity<Resource<UserDto>> findOne(@PathVariable("uuid") String uuid) {
Link link = linkTo(UserController.class).slash(uuid).withSelfRel();
UserDto user = userFacade.show(uuid);
Resource<UserDto> userResource = new Resource<>(user, link);
return ResponseEntity.ok(userResource);
}
@DeleteMapping(value = "/{uuid}")
ResponseEntity<UserDto> delete(@PathVariable("uuid") String uuid) {
UserDto user = userFacade.delete(uuid);
return ResponseEntity.ok(user);
}
}
UserFacade (Korzystam z architektury hexagonalnej/ports&adapters i CQRS, stąd fasada)
@Transactional
@RequiredArgsConstructor
@Component
public class UserFacade {
private final UserRepository userRepository;
private final UserCreator userCreator;
public UserDto add(UserDto userDto) {
Objects.requireNonNull(userDto);
User user = userCreator.from(userDto);
user = userRepository.save(user);
return user.dto();
}
public UserDto show(String uuid) {
Objects.requireNonNull(uuid);
User user = userRepository.findOneOrThrow(UUID.fromString(uuid));
return user.dto();
}
public Page<UserDto> findAll(Pageable pageable) {
Objects.requireNonNull(pageable);
return userRepository.findAll(pageable).map(User::dto);
}
public UserDto delete(String uuid) {
Objects.requireNonNull(uuid);
User user = userRepository.findByUuid(UUID.fromString(uuid));
User deletedUser = userRepository.deleteById(user.getId());
return deletedUser.dto();
}
}
UserRepository
interface UserRepository extends Repository<User, Integer> {
User save(User user);
User findById(int id);
User findByUuid(UUID uuid);
Page<User> findAll(Pageable pageable);
User deleteById(int id);
User deleteByUuid(UUID id);
default User findOneOrThrow(UUID uuid) {
User user = findByUuid(uuid);
if (user == null) {
throw new UserNotFoundException("Cannot find " + uuid);
}
return user;
}
default User findOneOrThrow(int id) {
User user = findById(id);
if (user == null) {
throw new UserNotFoundException("Cannot find " + id);
}
return user;
}
}
User
@Entity
@Getter
@Setter
class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Type(type="pg-uuid")
private UUID uuid;
// ...
}