你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

一段令人难以置信的烂代码

[复制链接]
gaosmile 发布时间:2020-9-28 10:24
在Facebook网站上有一个名为“Il Programmatore di Merda”(“ The Shitty Programmer”,中文俗译为“粑粑程序猿”)的社区。我经常上去浏览,这个网站经常分享一些写的烂的代码和有关编程的话题。这不,今天我就看到一段令人难以置信的烂代码,有图有真相:

微信图片_20200928102329.jpg
本周最烂代码

请各位仔细查看,上面的代码错误太多,我一时不知该从哪儿说起。

如果你是一个初级开发工程师,本篇文章会帮你理解上述代码中存在的一些严重的bug,希望各位同学引以为鉴。

128 行错误代码
我将上面的代码摘录下来,以便后面一起来讨论。代码如下:

  1. <script>
  2. function authenticateUser(username, password) {
  3.   var accounts = apiService.sql(
  4.     "SELECT * FROM users"
  5.   );

  6.   for (var i = 0; i < accounts.length; i++) {
  7.     var account = accounts [i];
  8.     if (account.username === username &&
  9.         account.password === password)
  10.     {
  11.       return true;
  12.     }
  13.   }
  14.   if ("true" === "true") {
  15.     return false;
  16.   }
  17. }

  18. $('#login').click(function() {
  19.   var username = $("#username").val();
  20.   var password = $("#password").val();

  21.   var authenticated = authenticateUser(username, password);

  22.   if (authenticated === true) {
  23.     $.cookie('loggedin', 'yes', { expires: 1 });
  24.   } else if (authenticated === false) {
  25.     $("error_message").show(LogInFailed);
  26.   }
  27. });
  28. </script>
复制代码

把代码复制完的一时之间,我竟不知道从何说起了。上述错误大致分为 3 类:

  • 安全问题
  • 基本编程概念问题
  • 代码格式化问题


2 安全问题

我们非常确定以下代码能够在客户端运行,因为它已经包含在两个<script>标记间(当然它用的是 jQuery 框架)。不要误会我的意思,这些代码即使是运行在服务器端也很糟糕,在客户端上运行这些代码会将数据库暴露给……每个用户。

让我们先来看一下authenticateUser函数:

  1. function authenticateUser(username, password) {
  2.   var accounts = apiService.sql(
  3.     "SELECT * FROM users"
  4.   );

  5.   for (var i = 0; i < accounts.length; i++) {
  6.     var account = accounts [i];
  7.     if (account.username === username &&
  8.         account.password === password)
  9.     {
  10.       return true;
  11.     }
  12.   }
  13.   if ("true" === "true") {
  14.     return false;
  15.   }
  16. }
复制代码

我们的代码在某些地方有个叫做apiServices的接口,它公开了一个.sql方法,可以对数据库进行 SQL 操作。这意味着,如果你在运行上述代码的浏览器上打开控制台,就可以执行各种查询,安全隐患简直无法比喻。例如,你不需要获得授权就可以这样做:

  1. apiService.sql("show tables;");
复制代码

调用上述 API,代码执行后会返回数据库的所有表名称。

我们暂且假装这不是一个特严重的问题。但是请各位接着往下看:

  1. if (account.username === username && account.password === password)
复制代码

所以,作者的意思是直接保存了用户所有的明文密码,而没有对它们进行MD5哈希处理?

这简直无法想象!现在我可以打开 Chrome 浏览器的调试器,直接查看每个用户的明文密码。

我非常确定,很大一部分用户会在社交网络、邮件服务、银行账户等服务中使用相同的用户名和密码。想象一下,别人可以在没有任何障碍下就可以拿到你的账户与密码,这是得多么地可怕。

作者尝试设置登录cookie 的方式也存在问题。代码如下:

  1. $.cookie('loggedin', 'yes', { expires: 1 });
复制代码

按照代码的意思,作者使用 jQuery 设置 cookie,让该 cookie 告知 Web 应用程序用户是否通过身份验证。

好吧,千万不要使用 JavaScript 来设置此类 cookie。

如果你有存储此类登陆信息的需求,那么使用 cookie 确实是最常见的解决方案,这没有什么问题!但是使用 JavaScript 设置它们意味着你无法设置httpOnly属性,这会导致每个恶意脚本都能轻而易举地访问和获取你的 cookie 内容。

是的,我知道,他们只是存储'loggedin': 'yes'的键值信息,可能不是上面我讲的那种情况,但总之这是一个糟糕的做法。

另外,打开 Chrome 控制台,我随时可以输入$ .cookie('loggedin','yes',{expires: 1000000000000})命令, 而且即使我没有用户帐户,也会永远保持登录状态。

3 基本编程概念问题
想说的话太多,但无奈时间有限。

很明显,authenticateUser函数写的就是一堆垃圾,该函数的实现充分表明作者缺乏一些基本的编程概念。

  1. function authenticateUser(username, password) {
  2.   var accounts = apiService.sql(
  3.     "SELECT * FROM users"
  4.   );

  5.   for (var i = 0; i < accounts.length; i++) {
  6.     var account = accounts [i];
  7.     if (account.username === username &&
  8.         account.password === password)
  9.     {
  10.       return true;
  11.     }
  12.   }
  13.   if ("true" === "true") {
  14.     return false;
  15.   }
  16. }
复制代码

代码作者为什么不只查询给定用户名和密码的用户,而是检索出数据库中的所有用户呢?如果该数据库中拥有数百万个用户怎么办?

还有前面我已经说过了,在这里我再提一下,为什么作者不对数据库中的明文密码进行哈希处理?

让我们接着看一下authenticateUser函数的返回值。

我们可以看到,该函数接收两个 string 类型的参数,最后返回一个布尔类型的值。所以,下面的代码即使很糟糕(明文密码),但也有一定的意义:

  1. for (var i = 0; i < accounts.length; i++) {
  2.   var account = accounts [i];
  3.   if (account.username === username &&
  4.       account.password === password)
  5.   {
  6.     return true;
  7.   }
  8. }
复制代码

上面代码的含义很清楚,“是否存在具有 X 用户名和 Y 密码的用户?是的,所以函数执行结果返回 true”。

但是下面这个代码的逻辑这样的:

  1. if ("true" === "true") { return false;}
复制代码

这根本没有任何道理!为什么函数不去掉永真条件判断,直接返回 false?继续接着分析后面的代码:

  1. $('#login').click(function() {
  2.   var username = $("#username").val();
  3.   var password = $("#password").val();

  4.   var authenticated = authenticateUser(username, password);

  5.   if (authenticated === true) {
  6.     $.cookie('loggedin', 'yes', { expires: 1 });
  7.   } else if (authenticated === false) {
  8.     $("error_message").show(LogInFailed);
  9.   }
  10. });
复制代码

使用 jQuery 获取属性值的代码部分没有什么问题。问题在于它如何处理loggedin 用户的 cookie。

以前讨论过这样一个问题,我可以在我的 Chrome 控制台输入$ .cookie('loggedin','yes',{expires:1}); 保持认证一整天,甚至都不需要一个帐号。

所以,这个网站到底是怎么确定我是谁的?也许它只是通过用户名 / 密码身份验证显示一些私人内容,所以它没有展示任何个人数据。总之,没有人知道代码为什么会这么写。

4 代码格式化问题

代码格式可能是整个代码中不太重要的部分,但我们可以很容易地判断出该开发人员复制 / 粘贴了某些网站上的代码。

下面的代码片段,我们可以看到开发者使用了双引号引用字符串:

  1. var username = $("#username").val();
  2. var password = $("#password").val();
复制代码

然而,下面的代码却又使用了单引号字符串:

  1. $.cookie('loggedin', 'yes', { expires: 1 });
复制代码

这些看起来可能没有那么重要,但实际上我们可以确定,开发人员可能已经从 StackOverflow 复制粘贴了一些代码,甚至都没有遵循整个代码库的代码规范来重写它们。当然,这只是一个小问题,但它表明开发人员并不真正关心和理解代码的工作方式,只是希望代码以某种方式工作。

大家不要误会,我每天都会在 Google 上进行搜索,但比起仅仅复制和粘贴代码来实现功能,理解代码的工作原理——比如理解如何设置 Cookie,实际上更为重要。如果由于某种原因整个进程中断了怎么办?你如何确定是脚本的哪一部分不起作用呢?

5 总结
我绝对可以确定上面的代码是伪造的。这是我第一次看到使用同步方式进行 SQL 查询:

  1. var accounts = apiService.sql( "SELECT * FROM users");
复制代码

通常,我希望查询功能的实现类似下面这样:

  1. var accounts = apiService.sql("SELECT * FROM users", (err, res) => { console.log(err); // some error console.log(res); // query result});
复制代码

或者这样:

  1. var accounts = await apiService.sql( "SELECT * FROM users");
复制代码

即使使用同步方式调用apiService.sql返回查询值(我对此表示怀疑),在内部也必须进行与数据库的连接、执行查询语句并发送返回查询结果,这些过程(你可能已经知道了)明显是不同步的。

但是,即使上面的代码不是伪造的,我也可以确信它是由初级开发人员编写的。我刚刚开始入行写代码的一段时间里,我很确定自己为之前的公司也写过这么糟糕的代码。

这个锅不能甩给初级开发人员。

让我们假设上面的代码是真实的。这里的初级开发人员正在竭尽所能实现功能。他 / 她尚未开始学习如何正确处理 SQL 查询、cookie 以及其他需要注意的技术点,这完全可以理解!

高级开发人员应该提供某种形式的指导,以确保初级开发人员可以理解他们的错误,保证这样的错误代码不会在生产环境中使用。

我也可以确认的是,有些公司其实并不真正在乎开发人员编写的代码质量。
代码能解决问题吗?——生产环境部署一下就知道了呀。代码是由初级开发人员编写的,甚至都没有高级开发人员的批准吗?——部署运行一下就知道结果了呀。
哎,Shit happens!

6 后记
我在 Reddit 对此进行了一番讨论后,一个非常给力的小伙伴分享了下面的 Reddit 话题:

“This JavaScript code powers a 1,500 user intranet application”
https://www.reddit.com/r/programminghorror/comments/66klvc/this_javascript_code_powers_a_1500_user_intranet

所以,是我错了。这些代码并不是伪造的!

收藏 评论0 发布时间:2020-9-28 10:24

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版