1. 程式人生 > >sql注入攻擊和PreparedStatement有效防止sql注入攻擊

sql注入攻擊和PreparedStatement有效防止sql注入攻擊

【1】sql注入攻擊:

/**
	 * SQL 注入.
	 */
	@Test
	public void testSQLInjection() {
		String username = "a' OR PASSWORD = ";
		String password = " OR '1'='1";

		String sql = "SELECT * FROM user_tbl WHERE user_name = '" + username
				+ "' AND " + "password = '" + password + "'";
		// sql注入攻擊使用的sql: SELECT * FROM user_tbl WHERE user_name = 'a' OR PASSWORD = ' AND password = ' OR '1'='1'
		System.out.println(sql);

		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;

		try {
			connection = JdbcUtils.getConnection();
			statement = connection.createStatement();
			resultSet = statement.executeQuery(sql);

			if (resultSet.next()) {
				System.out.println("登入成功!");
			} else {
				System.out.println("使用者名稱和密碼不匹配或使用者名稱不存在. ");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.closeStatAndConnAndResultSet(statement, connection, resultSet);
		}
	}
	

【2】PreparedStatement 有效防止sql注入攻擊

/**
	 * 使用 PreparedStatement 將有效的解決 SQL 注入問題.
	 */
	@Test
	public void testSQLInjection2() {
		String username = "a' OR PASSWORD = ";
		String password = " OR '1'='1";

		String sql = "SELECT * FROM user_tbl WHERE user_name = ? "
				+ "AND password = ?";

		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;

		try {
			connection = JdbcUtils.getConnection();
			preparedStatement = connection.prepareStatement(sql);

			preparedStatement.setString(1, username);
			preparedStatement.setString(2, password);

			resultSet = preparedStatement.executeQuery(); // 這裡查詢失敗
			
			if (resultSet.next()) {
				System.out.println("登入成功!");
			} else {
				System.out.println("使用者名稱和密碼不匹配或使用者名稱不存在. ");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.closeStatAndConnAndResultSet(preparedStatement, connection, resultSet);
		}
	}

【3】程式碼補充:jdbc工具類 

/**
 * 操作jdbc的工具類-封裝了一些工具方法
 * @author pacoson
 */
public class JdbcUtils {
	
	
	
	/**
	 * 通用的更新方法:insert, update, delete
	 * 版本1
	 * @param sql
	 */
	public static void updateV2ByPreparedStatement(String sql, Object... objs) {
		Connection conn = null;
		PreparedStatement stat = null;
		try {
			// 1.獲取資料庫連線
			conn = JdbcUtils.getConnection();
			// 4.執行插入
			// 4.1 獲取操作sql語句的statement物件; 
//			呼叫Connection的  createStatement() 方法來獲取
			stat = conn.prepareStatement(sql);
			int i = 1;
			for (Object obj : objs) {
				stat.setObject(i++, obj);
			}
			System.out.println("連線=" + conn + ",語句 = " + stat);
			// 4.2 呼叫statement物件的 executeUpdate(sql) 執行sql語句進行插入
			int updateRows = stat.executeUpdate();
			System.out.println("更新記錄行數:" + updateRows);
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.closeStatAndConn(stat, conn);
		}
	}
	
	/**
	 * 通用的更新方法:insert, update, delete
	 * 版本1
	 * @param sql
	 */
	public static void updateV1(String sql) {
		Connection conn = null;
		Statement stat = null;
		try {
			// 1.獲取資料庫連線
			conn = JdbcUtils.getConnection();
			// 4.執行插入
			// 4.1 獲取操作sql語句的statement物件; 
//			呼叫Connection的  createStatement() 方法來獲取
			stat = conn.createStatement();
			System.out.println("連線=" + conn + ",語句 = " + stat);
			// 4.2 呼叫statement物件的 executeUpdate(sql) 執行sql語句進行插入
			int updateRows = stat.executeUpdate(sql);
			System.out.println("更新記錄行數:" + updateRows);
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.closeStatAndConn(stat, conn);
		}
	}
	
	/**
	 * 獲取連線的方法。
	 * 通過讀取配置檔案從資料庫伺服器獲取一個連線
	 * @return
	 * @throws Exception
	 */
	public static Connection getConnection() throws Exception {
		
		// 讀取類路徑下的 jdbc.properties 檔案並將其封裝到 Properties中:
		InputStream in = JdbcTest01.class.getClassLoader().getResourceAsStream("jdbc.properties");
		Properties props = new Properties();
		props.load(in);
		/* 通過反射獲取驅動器Driver */
		Driver driver = (Driver) Class.forName(props.getProperty("driver")).newInstance();
		/* 獲取資料庫連線  */
		Connection conn = driver.connect(props.getProperty("url"), props);
		return conn;
	}
	
	/**
	 * 關閉資料庫語句 statement 和 資料庫連線 conn 和 結果集 ResultSet
	 * @param stat
	 * @param conn
	 */
	public static void closeStatAndConnAndResultSet(Statement stat, Connection conn, ResultSet rs) {
		if (null != rs) {
			try {
				rs.close(); // 關閉ResultSet物件
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		if (null != stat) {
			try {
				stat.close(); // 關閉statement物件
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		if (null != conn) {
			try {
				conn.close(); // 關閉連線
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * 關閉資料庫語句 statement 和 資料庫連線 conn 
	 * @param stat
	 * @param conn
	 */
	public static void closeStatAndConn(Statement stat, Connection conn) {
		if (null != stat) {
			try {
				stat.close(); // 關閉statement物件
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		if (null != conn) {
			try {
				conn.close(); // 關閉連線
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
}