【发布时间】:2026-01-18 14:30:01
【问题描述】:
createNativeQuery() 是否可以安全地防止 SQL 注入:
@ManagedBean
@ViewScoped
public class UserController {
@PersistenceContext
private EntityManager em;
public User register(User u) {
Query query = em.createNativeQuery("SELECT r1_register(?,?,?,?,?,?,?)");
short i = 0;
query.setParameter(++i, u.getUsername());
query.setParameter(++i, u.getPassword());
query.setParameter(++i, u.getName());
query.setParameter(++i, u.getSurname());
query.setParameter(++i, u.getEmail());
query.setParameter(++i, u.getBirthdate());
query.setParameter(++i, u.getPhoneNumber());
int id = (int) query.getSingleResult();
if (id != 0) u.setIduser(id);
return u;
}
}
r1_register 是一个存储函数,它执行 INSERT 并返回新插入用户的 id。这是否等效:
public User register(User u) {
em.persist(u);
// get the last inserted id (user id must be @Generated)
em.flush(); // user id set here
return u;
}
u 在这两种情况下都由用户填写。最后是默认发起的事务吗?
编辑:例程:
CREATE DEFINER=`root`@`localhost` FUNCTION `r1_register`(username VARCHAR(45),
_password VARCHAR(45),
_name VARCHAR(45),
surname VARCHAR(45),
_email VARCHAR(45),
_birthdate DATE,
phone_number VARCHAR(10) ) RETURNS int(11)
BEGIN
-- Adds a new user.
-- START TRANSACTION; -- Begin a transaction -- NOT ALLOWED
-- http://*.com/questions/16969875/
IF r1_check_unique_username(username)=0 THEN
RETURN 0;
END IF;
INSERT IGNORE INTO `hw1_db`.`users` (`username`, `password`, `name`, `surname`, `email`, `birthdate`, `phone_number`)
VALUES (username, _password, _name, surname, _email, _birthdate, phone_number);
-- see: http://*.com/a/5939840/281545
-- The drawback to this approach is that you cannot go back and use
-- ids wasted because of failed attempts to INSERT IGNORE in the event
-- of a duplicate key. Shouldn't be a problem for us as we check.
-- /Transaction
-- IF ROW_COUNT() > 0 THEN
-- ROW_COUNT() returns the number of rows updated/inserted/deleted
-- COMMIT; -- Finalize the transaction
-- ELSE
-- ROLLBACK; -- Revert all changes made before the transaction began
-- END IF;
RETURN LAST_INSERT_ID();
END
【问题讨论】:
-
一般情况下,参数化 SQL 构造(例如
PreparedStatement)默认转义特殊字符,这样可以防止普通 SQL 注入 -
@kolossus: 是的,我问的是 JPA api - 例如
persist(Entity e)在内部转义它持续存在的实体的字符串字段
标签: jpa ejb sql-injection entitymanager