2014-02-08 40 views
0

如果用作是createNativeQuery()安全對SQL注入:的EntityManager創建本地查詢VS堅持和注射

@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://stackoverflow.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://stackoverflow.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 
+0

通常,參數化SQL結構(例如'PreparedStatement')默認情況下會轉義特殊字符,並且這樣做,您可以防範vanilla SQL注入 – kolossus

+0

@kolossus:是的我詢問JPA api - 例如'persist (Entity e)'內部轉義實體的字符串字段它堅持 –

回答

1

這取決於什麼r1_register實際上做的事情。如果它只是保存用戶而沒有別的,比是的,它們是相同的,因爲這就是EntityManager#persist正在做的事情。但是,如果DB函數正在執行一些安全檢查或寫入其他表,則還需要在JPA中實現它。順便說一句,用於插入User並獲得ID代碼應該是

public User register(User u) { 
    em.getTransaction().begin(); 
    em.persist(u); 
    em.getTransaction().commit(); 
    int id = u.getId(); 
    return u; 
} 

但你不必叫EntityManager#flush如果你需要該ID的register方法被調用後,沖水是由每個交易結束時進行。

+0

因此,他們都防範sql感染?他們也都開始交易? Mycode如所見。另外'e.getId();'?沒有e變量 –

+0

對不起,我的意思是'u'。那麼'EntityManager'肯定可以保護你免受SQL注入。不,事務通過在'EJB' bean或通過'em.getTransaction()。begin();'進入方法而受到損害。 –

+0

你錯了我害怕'em.persist(u);'帶或不帶flush _does沒有設置id_ - 'System.out.println(「USER id:」+ u.getIduser());'打印0。我仍然懷疑注射是否被阻止 - 我很驚訝他們沒有在文檔中提到它。此外,我仍然不確定有交易正在進行 - 你能否提供一些鏈接? –