当前位置: 首页 > news >正文

商丘加盟小吃网站中煤建设协会网站

商丘加盟小吃网站,中煤建设协会网站,企业网站建设综合实训心得体会,公司改名字重新备案网站会停吗文章目录 HOTP 的基础原理HOTP 的工作流程HOTP 的应用场景HOTP 的安全性安全性增强措施Code生成HOTP可配置项校验HOTP可拓展功能计数器#xff08;counter#xff09;计数器在客户端和服务端的作用计数器的同步机制客户端和服务端中的计数器表现服务端如何处理计数器不同步计… 文章目录 HOTP 的基础原理HOTP 的工作流程HOTP 的应用场景HOTP 的安全性安全性增强措施Code生成HOTP可配置项校验HOTP可拓展功能计数器counter计数器在客户端和服务端的作用计数器的同步机制客户端和服务端中的计数器表现服务端如何处理计数器不同步计数器在客户端和服务端的举例如何在 Java 实现中体现计数器小结 一个服务端程序应对多个客户端关键问题解决方案1. 计数器的存储和管理2. 服务端管理多个客户端计数器的架构3. 具体实现步骤4. Java 示例代码 关键点解释进一步优化小结 计数器容错机制验证失败常见原因1. 计数器不同步2. 密钥不匹配3. 编码问题4. 生成 OTP 时计数器没有递增5. 输入 OTP 错误解决方案 HOTP 的基础原理 HOTP 是基于 HMACHash-based Message Authentication Code算法的一种一次性密码生成机制。其核心思想是通过计数器的变化和共享密钥生成一次性密码。每次使用时计数器递增因此每个密码只能使用一次。 它遵循 RFC 4226 标准。 核心组件 共享密钥K服务器和客户端事先约定并保存的密钥。计数器C每生成一个一次性密码计数器值增加确保密码的唯一性。HMAC 算法使用 HMAC-SHA-1 或其他 HMAC 哈希算法结合共享密钥和计数器生成动态密码。 生成公式 HOTP(K, C) HMAC-SHA-1(K, C) mod 10^6其中 K 是共享密钥。C 是计数器。输出值取前 6 位数字或更多取决于配置通常为 6 位数字密码。 HOTP 的工作流程 HOTP 的密码生成和验证基于计数器的增量。具体步骤如下 密码生成 客户端和服务器预先共享一个密钥 K。每次生成密码时客户端使用当前计数器值 C 和密钥 K 计算 HMAC 值。从 HMAC 结果中截取 6 位或 8 位数字生成一次性密码。 密码验证 服务器接收到客户端的密码后使用相同的共享密钥 K 和当前计数器值 C 生成 HMAC 值。如果生成的 HMAC 值与客户端提供的密码匹配认证成功服务器递增计数器 C。服务器通常允许一定的容错窗口如 ±2 个计数器值以防止由于计数器不同步导致的验证失败。 HOTP 的应用场景 HOTP 广泛应用于需要基于事件或计数器的系统中典型场景包括 硬件令牌银行、企业安全系统等早期使用的物理设备用户通过令牌生成动态密码。基于事件的身份验证系统每当发生某些特定事件如用户发起登录请求或支付请求时系统使用 HOTP 生成密码。离线环境由于 HOTP 不依赖时间因此在网络连接不稳定或设备无法持续联网的场景下尤为适用。 HOTP 的安全性 优势 基于事件驱动HOTP 的密码生成依赖于计数器用户可以在不依赖时间同步的情况下生成一次性密码适用于网络不稳定或离线操作场景。兼容性强HOTP 算法简单易于实现且支持广泛的设备和系统。无时间同步问题由于它基于计数器而非时间客户端和服务器之间无需保持时间同步。 潜在问题 密码有效期较长HOTP 密码在未使用前一直有效因此可能被攻击者截取后重放。这一点使得它在安全性方面较 TOTP 弱。计数器同步问题客户端和服务器的计数器需要同步。如果用户多次生成密码但没有使用则可能导致计数器不同步。为此服务器通常允许一个容错窗口但这也可能被攻击者利用来猜测计数器的值。有限容错窗口可能被滥用服务器在验证时允许的容错窗口可能导致暴力破解攻击即攻击者尝试多个计数器值直到找到有效的密码。 安全性增强措施 设置较短的密码有效期在服务端设置较短的密码有效期确保未使用的 HOTP 密码快速失效。配合其他身份验证手段与二次身份验证或生物识别等方法结合使用防止密码被重放攻击或暴力破解。动态调整容错窗口服务器可以根据用户行为动态调整容错窗口的大小以减少密码被暴力破解的风险。 Code 生成HOTP 基于 HMAC-SHA-256 算法生成一次性密码OTP。 我们使用了 javax.crypto 包中的 HMAC 相关类来实现 HMAC-SHA-356 算法并生成 6 位的 OTP。 package com.artisan.otp.hotp;import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger;/*** author 小工匠* version 1.0* date 2024/10/1 21:22* mark: show me the code , change the world*/public class HOTP {// 生成HOTP码public static String generateHOTP(String key, long counter, int digits) throws Exception {// 将key转换为字节数组byte[] keyBytes hexStr2Bytes(key);// 计算HMAC-SHA-1byte[] counterBytes longToBytes(counter);byte[] hmacResult hmacSHA1(keyBytes, counterBytes);// 获取动态截取码Dynamic Truncationint otp dynamicTruncate(hmacResult) % (int) Math.pow(10, digits);// 格式化OTP为固定长度不足位数用0填充return String.format(%0 digits d, otp);}// 使用HmacSHA256生成hashprivate static byte[] hmacSHA1(byte[] key, byte[] counter) throws Exception {// HmacSHA1 HmacSHA256SecretKeySpec signKey new SecretKeySpec(key, HmacSHA256);Mac mac Mac.getInstance(HmacSHA256);mac.init(signKey);return mac.doFinal(counter);}// 动态截取Dynamic Truncationprivate static int dynamicTruncate(byte[] hmacResult) {// 取HMAC结果的最后字节的低4位作为偏移量int offset hmacResult[hmacResult.length - 1] 0xf;// 从偏移位置起取4个字节组成一个31位的整数return ((hmacResult[offset] 0x7f) 24) |((hmacResult[offset 1] 0xff) 16) |((hmacResult[offset 2] 0xff) 8) |(hmacResult[offset 3] 0xff);}// 将long类型的计数器转换为字节数组8字节private static byte[] longToBytes(long value) {return BigInteger.valueOf(value).toByteArray();}// 将十六进制字符串转换为字节数组private static byte[] hexStr2Bytes(String hex) {byte[] bytes new byte[hex.length() / 2];for (int i 0; i bytes.length; i) {bytes[i] (byte) Integer.parseInt(hex.substring(2 * i, 2 * i 2), 16);}return bytes;}public static void main(String[] args) {try {// 测试HOTP生成String secret 3132333435363738393031323334353637383930; // 十六进制密钥long counter 1; // 计数器int digits 6; // OTP长度String hotp generateHOTP(secret, counter, digits);System.out.println(Generated HOTP: hotp);} catch (Exception e) {e.printStackTrace();}} } 代码解释 密钥 (key)密钥为一个十六进制字符串表示的共享密钥转换为字节数组用于生成 HMAC。计数器 (counter)每次生成新的 OTP 时计数器递增。这是 HOTP 的核心机制。HMAC-SHA256使用 javax.crypto.Mac 类生成 HMAC-SHA256哈希值。动态截取 (dynamicTruncate)HOTP 的最后步骤根据哈希结果的偏移量提取 31 位的数值然后对其取模来生成 6 位的一次性密码。 运行结果 在 main 方法中使用一个示例密钥和计数器来生成 6 位的 HOTP。例如如果你使用的计数器为 1生成的 HOTP 可能是 638487。 可配置项 密钥长度可以使用更长的密钥建议密钥使用至少 160 位或 256 位的密钥如 SHA-256 或更高。OTP 位数digits 参数允许生成 6 位、7 位或 8 位等不同长度的 OTP。 校验HOTP 为了验证 HOTP我们需要客户端生成的 OTP 与服务器端生成的 OTP 一致。由于 HOTP 依赖于共享密钥和计数器所以我们要确保在客户端和服务器端使用相同的密钥和计数器值。 验证 HOTP 的 Java 实现 在下面的实现中服务器会接受用户输入的 OTP并与使用相同计数器生成的 OTP 进行比较。如果 OTP 匹配则验证成功。 package com.artisan.otp.hotp; import java.util.Scanner;public class HOTPVerifier2 {// 验证HOTPpublic static boolean verifyHOTP(String key, long counter, String inputOTP, int digits) throws Exception {// 生成服务器端的HOTPString serverHOTP HOTP.generateHOTP(key, counter, digits);// 比较用户输入的OTP和服务器生成的HOTPreturn serverHOTP.equals(inputOTP);}public static void main(String[] args) {try {// 设置密钥和计数器String secret 3132333435363738393031323334353637383930; // 与客户端一致的十六进制密钥long counter 1; // 当前计数器值int digits 6; // OTP长度Scanner scanner new Scanner(System.in);String inputOTP;boolean isValid;// 允许用户多次输入OTP进行验证while (true) {// 生成服务器端的HOTPString expectedHOTP HOTP.generateHOTP(secret, counter, digits);System.out.println(服务器生成的 HOTP: expectedHOTP);// 提示用户输入OTPSystem.out.print(请输入 OTP或输入 exit 退出);inputOTP scanner.nextLine();// 如果用户输入 exit 则退出程序if (inputOTP.equalsIgnoreCase(exit)) {System.out.println(退出验证程序。);break;}// 验证用户输入的OTP是否正确isValid verifyHOTP(secret, counter, inputOTP, digits);if (isValid) {System.out.println(验证成功OTP正确);// 验证成功后增加计数器counter;} else {System.out.println(验证失败OTP不正确);}System.out.println();}} catch (Exception e) {e.printStackTrace();}} } verifyHOTP该方法用于验证客户端生成的 OTP 是否与服务器生成的 OTP 相同。它会调用 HOTP.generateHOTP 方法生成服务器端的 OTP然后将其与用户输入的 OTP 进行比较。密钥 (key)服务器和客户端必须使用相同的密钥。此密钥在初始化时由双方共享。计数器 (counter)计数器确保每次生成的 OTP 都是唯一的。每验证一次 OTP计数器需要递增。OTP 位数 (digits)定义 OTP 的位数如 6 位、7 位或 8 位。 验证流程 生成服务器端的 OTP服务器根据密钥和计数器生成一个 OTP。用户输入 OTP用户在客户端生成 OTP 后在服务器端输入以进行验证。服务器验证 OTP服务器通过比较自己生成的 OTP 和用户输入的 OTP决定是否验证成功。 服务器和客户端使用相同的计数器值和密钥所以 OTP 匹配。如果输入的 OTP 错误服务器会显示验证失败。 可拓展功能 计数器同步在实际应用中计数器同步可能出现问题。你可以实现一个容错机制允许服务器在一定范围内例如±2个计数器接受 OTP 。安全提示为了提升安全性可以结合其他验证方式比如 IP 白名单、二次验证或时间限制等。 计数器counter 在 HOTPHMAC-based One Time Password机制中计数器counter 是保证 OTP一次性密码唯一性和安全性的重要组成部分。它在客户端和服务端都存在并且双方必须保持同步。 计数器在客户端和服务端的作用 客户端每次用户请求生成 OTP 时客户端都会使用当前的计数器值与共享密钥通过 HMAC-SHA-256 算法生成一次性密码OTP。客户端自己维护计数器每生成一次 OTP计数器可以递增。 服务端当服务端验证用户输入的 OTP 时它也使用同样的密钥和计数器生成相同的 OTP。为了验证成功服务端的计数器必须和客户端的计数器同步或相差在一个容忍窗口内如±2。每次验证成功后服务端也需要递增计数器以准备下一次验证。 计数器的同步机制 初始同步客户端和服务端通常从一个初始值开始比如 0 或 1。初始值在客户端和服务端协商时确定。由于计数器是由双方共享的客户端和服务端在初次使用时保持一致。 递增每次生成 OTP 后客户端和服务端的计数器都会递增。每当客户端生成一个 OTP 并输入服务器验证后也递增计数器。这样保证双方的计数器同步并确保下一个 OTP 的生成不会重复。 客户端和服务端中的计数器表现 客户端计数器 每当用户请求生成 OTP 时客户端会读取当前计数器值生成 OTP。在用户提交 OTP 后客户端可以选择递增计数器以生成下一个 OTP。如果客户端的计数器与服务端的计数器同步它们生成的 OTP 是相同的。 服务端计数器 服务端在接收到用户提交的 OTP 时会使用自己维护的计数器值生成 OTP并将其与用户的 OTP 进行比较。如果 OTP 匹配服务端验证成功并递增计数器。如果 OTP 不匹配服务端可以尝试在一定的计数器范围内如 ±1 或 ±2进行匹配以防止客户端和服务端的计数器不同步。 服务端如何处理计数器不同步 由于某些原因如客户端多次生成 OTP 而没有使用网络延迟等客户端和服务端的计数器可能会不同步。服务端可以通过以下策略处理这种情况 容错窗口window服务端在验证 OTP 时可以尝试在当前计数器值的基础上向前或向后偏移几个计数器值。例如服务端可以尝试使用 counter ± 1 或 counter ± 2 的值进行 OTP 验证。这种方式允许计数器有一个容错范围避免客户端和服务端不同步导致验证失败。 重同步机制某些系统中会通过一个重新同步流程来重新对齐客户端和服务端的计数器。例如如果检测到计数器不同步可以让客户端和服务端通过一个安全通道重新协商新的计数器值。 计数器更新服务端在验证成功后会更新自己的计数器值使其与客户端保持同步。 计数器在客户端和服务端的举例 客户端生成 OTP 假设当前客户端的计数器为 5密钥为 secret, 生成 OTP 为 123456。客户端显示 OTP 并递增计数器计数器更新为 6。 服务端验证 OTP 服务端接收到 OTP 123456当前计数器也是 5与客户端同步。服务端生成 OTP 123456 并验证成功然后将计数器更新为 6。 客户端下一次生成 OTP 客户端使用计数器值 6 生成新的 OTP例如654321提交给服务端。服务端的计数器也为 6生成相同的 OTP 并验证成功继续递增计数器。 如何在 Java 实现中体现计数器 在 Java 实现中计数器可以作为一个持久化的变量客户端和服务端都需要维护各自的计数器值。以下是计数器的处理流程 // 假设客户端生成OTP时计数器值为5 long clientCounter 5; String clientHOTP HOTP.generateHOTP(secret, clientCounter, digits); System.out.println(客户端生成的 OTP: clientHOTP);// 假设服务端当前计数器值为5 long serverCounter 5; boolean isValid HOTPVerifier.verifyHOTP(secret, serverCounter, clientHOTP, digits); if (isValid) {System.out.println(验证成功计数器同步);// 递增服务端的计数器serverCounter; } else {System.out.println(验证失败可能计数器不同步。); }小结 客户端和服务端的计数器同步 是 HOTP 正常工作的核心。容错机制 允许一定范围内的计数器不同步以提升用户体验。计数器持久化 是关键客户端和服务端在每次生成或验证后都要更新并保存计数器的值。 一个服务端程序应对多个客户端 当一个服务端程序需要处理多个客户端的 HOTP 验证时计数器counter 的管理变得更加复杂因为每个客户端都会有自己的计数器并且需要和服务端保持同步。为了确保 OTP 的唯一性和正确性服务端必须为每个客户端维护独立的计数器并正确更新计数器的状态。 关键问题 每个客户端都有独立的计数器每个客户端的计数器必须单独管理因为每个客户端的 OTP 会根据各自的计数器生成。持久化计数器服务端需要确保计数器在每次 OTP 验证后持久化以避免计数器不同步的风险。如果服务重启或在不同会话间需要从持久化存储中加载计数器。并发控制当多个客户端同时发起 OTP 请求时服务端需要确保对同一个客户端的计数器读写操作是线程安全的以防计数器状态被并发修改。 解决方案 1. 计数器的存储和管理 服务端可以为每个客户端使用独立的存储如数据库、内存缓存等来持久化和管理计数器。通常可以通过客户端的唯一标识符如用户 ID、设备 ID 等来关联计数器。 存储方式 数据库可以使用关系型数据库如 MySQL、PostgreSQL或 NoSQL 数据库如 Redis、MongoDB来存储每个客户端的计数器。内存缓存在高性能环境中使用内存缓存如 Redis存储计数器以便快速访问和更新。 2. 服务端管理多个客户端计数器的架构 服务端需要为每个客户端分配唯一的计数器。以下是服务端如何处理多个客户端的示例架构 客户端身份识别服务端需要使用某种方式来识别每个客户端例如用户 ID 或设备 ID。这样可以保证每个客户端有唯一的计数器。 计数器存储每个客户端的计数器可以存储在数据库或缓存中按客户端唯一 ID 来索引。 计数器读写的同步处理在多线程或并发请求的场景下确保对计数器的读写是线程安全的。可以使用锁机制来确保同一时刻只有一个请求在修改某个客户端的计数器。 3. 具体实现步骤 生成 OTP 当客户端请求生成 OTP 时服务端从数据库或缓存中读取该客户端的计数器生成 OTP并将计数器递增。 验证 OTP 当客户端发送 OTP 给服务端验证时服务端读取该客户端的计数器并用相同的密钥生成 OTP。服务端还可以允许一定范围的容错窗口如 counter ± 2来应对客户端和服务端的计数器不同步问题。验证成功后更新计数器并持久化。 4. Java 示例代码 以下是处理多个客户端的伪代码示例展示了如何为每个客户端维护独立的计数器。 package com.artisan.otp.hotp;import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class HOTPServer {// 使用ConcurrentHashMap存储每个客户端的计数器key为客户端IDvalue为计数器值private ConcurrentHashMapString, Long clientCounters new ConcurrentHashMap();// 使用一个锁来保证对每个客户端计数器的线程安全访问private Lock lock new ReentrantLock();// 模拟数据库存储的客户端密钥private ConcurrentHashMapString, String clientSecrets new ConcurrentHashMap();public HOTPServer() {// 初始化假设有两个客户端每个客户端都有一个共享密钥clientSecrets.put(client1, 3132333435363738393031323334353637383930);clientSecrets.put(client2, 3132333435363738393031323334353637383931);// 初始化计数器clientCounters.put(client1, 1L);clientCounters.put(client2, 1L);}// 生成OTP的函数传入客户端IDpublic String generateOTP(String clientId) throws Exception {lock.lock(); // 锁定以确保计数器的安全访问try {// 获取客户端的计数器和密钥Long counter clientCounters.get(clientId);String secret clientSecrets.get(clientId);if (counter null || secret null) {throw new Exception(客户端未注册);}// 生成OTPString otp HOTP.generateHOTP(secret, counter, 6);// 递增计数器并更新clientCounters.put(clientId, counter 1);return otp;} finally {lock.unlock(); // 解锁}}// 验证OTP的函数public boolean verifyOTP(String clientId, String inputOTP) throws Exception {lock.lock();try {// 获取客户端的计数器和密钥Long counter clientCounters.get(clientId);String secret clientSecrets.get(clientId);if (counter null || secret null) {throw new Exception(客户端未注册);}// 生成服务器端的OTPString serverOTP HOTP.generateHOTP(secret, counter, 6);// 验证客户端输入的OTPif (serverOTP.equals(inputOTP)) {// 验证成功后更新计数器clientCounters.put(clientId, counter 1);return true;} else {return false;}} finally {lock.unlock();}}public static void main(String[] args) {try {HOTPServer server new HOTPServer();String clientId client1;// 服务端生成OTPString otp server.generateOTP(clientId);System.out.println(生成的 OTP: otp);// 客户端提交OTPboolean isValid server.verifyOTP(clientId, otp);System.out.println(验证结果: (isValid ? 成功 : 失败));} catch (Exception e) {e.printStackTrace();}} }关键点解释 ConcurrentHashMap使用 ConcurrentHashMap 存储每个客户端的计数器这样可以在并发情况下安全地处理多个客户端的请求。 线程安全使用 ReentrantLock 确保对计数器的读写是线程安全的。每当一个客户端请求生成或验证 OTP 时服务端会锁定该客户端的计数器防止并发修改。 独立管理多个客户端通过客户端唯一的 ID如 clientId服务端可以独立管理每个客户端的计数器和密钥。 计数器递增每次成功生成或验证 OTP 后服务端都会递增相应客户端的计数器并持久化以确保下次生成的 OTP 是唯一的。 进一步优化 计数器持久化在生产环境中计数器需要持久化到数据库或缓存中如 Redis以保证即使服务重启后计数器也能正确恢复。 容错机制可以允许服务端在计数器一定范围内如 ±2进行 OTP 验证以应对客户端和服务端计数器不同步的问题。 并发优化如果某个客户端有大量并发请求可以进一步优化锁机制使用更细粒度的锁或分布式锁来提升性能。 小结 服务端需要为每个客户端单独维护计数器计数器与客户端的身份信息关联。使用线程安全的数据结构和锁机制来确保并发情况下计数器的正确性。持久化计数器以避免重启服务后丢失计数器状态并使用容错窗口来应对客户端与服务端的计数器不同步问题。 计数器容错机制 可以修改 verifyOTP 方法允许服务端在一定范围内例如 ±2验证 OTP以应对计数器不完全同步的问题 public boolean verifyOTP(String clientId, String inputOTP) throws Exception {lock.lock();try {// 获取客户端的计数器和密钥Long counter clientCounters.get(clientId);String secret clientSecrets.get(clientId);if (counter null || secret null) {throw new Exception(客户端未注册);}// 尝试在一定范围内验证 OTP容错窗口为 ±2int window 2; // 容错范围for (int i -window; i window; i) {// 使用当前计数器加上偏移量生成 OTPString serverOTP HOTP.generateHOTP(secret, counter i, 6);// 验证客户端输入的 OTPif (serverOTP.equals(inputOTP)) {// 验证成功后更新计数器clientCounters.put(clientId, counter i 1); // 更新到同步的计数器值return true;}}// 如果在窗口范围内都验证失败则返回falsereturn false;} finally {lock.unlock();} }验证失败常见原因 1. 计数器不同步 在 HOTP 中计数器在每次生成 OTP 后都会递增。为了保证 OTP 的有效性服务端和客户端的计数器必须同步。如果在 OTP 生成和验证的过程中服务端的计数器和客户端不一致OTP 验证会失败。 2. 密钥不匹配 HOTP 基于 HMAC 算法需要服务端和客户端共享同一个密钥。如果在代码中客户端和服务端使用了不同的密钥会导致生成的 OTP 不同从而验证失败。 3. 编码问题 HOTP 的密钥需要经过 Base32 或 Base64 编码有时密钥的编码格式可能不一致导致 OTP 计算出现偏差。 4. 生成 OTP 时计数器没有递增 如果客户端生成 OTP 后没有递增计数器服务端在验证时会发现生成的 OTP 和当前计数器不匹配从而验证失败。 5. 输入 OTP 错误 如果用户输入的 OTP 有误例如少了前导零或者格式不对即使客户端和服务端的密钥和计数器同步也会导致验证失败。 解决方案 检查计数器同步确保生成 OTP 时客户端和服务端使用相同的计数器值。客户端的计数器每次生成 OTP 后应递增而服务端在验证时也应同步递增。 检查密钥一致性确保客户端和服务端使用相同的共享密钥并且该密钥的编码一致通常是 Base32。 增加容错窗口可以允许服务端在一定范围内如 counter ± 1 或 counter ± 2接受 OTP以应对计数器稍微不同步的情况。可以修改验证部分的逻辑允许在一定范围内检查 OTP。
http://www.zqtcl.cn/news/283622/

相关文章:

  • 房产证查询系统官方网站购买网站域名
  • 高端企业门户网站建设服务公司深圳企业网站怎么做
  • 页游网站如何做推广平面图设计软件有哪些
  • 自建网站有哪些wordpress 评论增加字段
  • 企业网站建设的方案书pc网站 公众号数据互通
  • 东莞设计制作网站制作做的asp网站手机号码
  • 必须做网站等级保护网站软件免费下载安装
  • 广州天河 网站建设上海招标网站
  • 云南网站建设方案专业的徐州网站开发
  • 政务服务 网站 建设方案郑州网站建设公司电话多少
  • 优化网站浏览量怎么看建设网站公司专业服务
  • php做的网站预览单产品网站建设
  • 网站文件验证上海推广网站公司
  • 如何免费申请网站外贸工艺品网站建设
  • 有名的wordpress网站网站开发企业培训
  • 中国建设银行绑定网站南宁seo如何做
  • 饮食类网站律师资格证报考条件
  • 昆明网站建设推广房源管理免费系统
  • jsp网站开发书籍环保网站 怎么做
  • 深圳营销型网站建设公司搜狗短网址生成
  • 如何优化购物网站建设广州seo公司排行
  • iis5.1 新建网站舆情系统的作用
  • 北京国互网网站建设公司东莞寮步搬家公司
  • 学校门户网站是什么意思做网站的意义大不大
  • 做网站卖酒网站内容建设的布局和结构
  • 效果图在哪个网站可以找比较好wordpress网站背景设置
  • 专业整站优化韩国设计公司网站
  • 网站建设与规划学的心得体会WordPress主题启用出现错误
  • 网站建设 资讯宁波东方论坛首页
  • 东莞网站制作有名 乐云践新郑州官方网