Hackers are out there to get your server. They are smart, numerous, and have only one thing in mind: getting in. They could be anybody—internal and external individuals or groups. They have many smart tools to choose from, however persistence is their greatest weapon. Paranoia is your best defense.
This may sound extreme, but correct planning for internal and external security is needed in environments where sensitive data and applications are manipulated. Keeping your systems correctly tuned and configured will help you avoid trouble.
Your security policy has to make the appropriate compromises between an environment with tight access checks and detailed auditing where almost no resource can be shared, and a resource-oriented or task-oriented environment, where a coarser granularity on identity may be acceptable in exchange for more opportunities for resource sharing and pooling. Remember, if you don't have a security policy, you don't have security, period. Any implementation effort has to have security thought into it from the first day.
References
Deciding Where To Enforce Security
Using Distributed COM with Firewalls
Change the Default Passwords
An incredible amount of critical information—financial, marketing, personal—has been stolen off the Internet not only because of deficient security architectures, but because databases and systems were irresponsibly left with their default installation passwords. If you don't want to be part of this group, be sure to change the default login passwords for well-known users in the RDBMS, Windows NT computer, and other resource.
This is not a securing-your-system checklist, but rather a don't-get-caught-with-your-pants-down reminder:
- Change the SQL Server "sa" user password to something other than blank. Don't use a dummy value such as password, sa, secret, and so on.
- Do not hardcode user names or passwords in ASP pages. These may be handed around artists, localization engineers, translators, and so forth.
- Keep secure information in secure data stores, such as the registry and file system. Make your application load passwords at run-time from the registry or the file system.
If an outside attacker has a means of attempting to log in to internal resources, you will need to reconfigure your firewall and network architecture. Changing the password is a first step, but attacks are going to be persistent and the hacker may eventually get in. Auditing failed attempts is always a good source to consider as well.
See the Use UDL Files to Persist Connection Strings section for more helpful links.
Check Security at the Door
There are many ways and places to perform security checks. However, one good practice always prevails—check security on the first entry point possible. This simplifies administration, decouples your application from the resources it uses, and improves its scalability by not forcing it to waste time doing things that will fail later.
More Information
Generally, you can check security and put barriers either at the entry point—setting restrictions on who may call components—or at the resource levels—setting restrictions on who may update a table. While checking security at resource levels seems enough at a first glance, this decision decreases the opportunities for growth and flexibility.
You must ensure that you're not making a business logic security check at the data layer. For example, you don't want to setup your application so that the permission to add a customer is enforced by allowing or denying INSERTS on a Customer's table. This model may eventually fail if your application grows. What happens if you need to send the customer e-mail?
This results in a layer mix-up, tying together the security of the components to both the administration and implementation of the back-end resources they use.
How To
Set security using roles on your objects. Group methods on your front-line objects so that classes are more task-oriented, rather than entity-oriented—a Transfers class versus Checking and Saving classes for example. This will make administration easier, allowing you to set permission at object/interface level rather than method level.
References
Assigning Roles to Components, Interfaces, or Methods
Deciding Where To Enforce Security
Use Roles to Set Security for Your Application
The idea of Roles is to abstract the application's security namespace from the network or domain namespace, and to allow your code to react to being used by different application actors instead of specific users. These actors may represent groups of people (managers) or applications (banking components).
You can use roles declaratively (just like setting permissions on a file) or programmatically from within your business logic code.
More Information
Hard-coding user identities, group names, or other domain or network information in your code couples your application to your particular security mechanisms and network namespace, not to mention to your network administrator. Your application will probably break when your administration procedures change or when a security reorganization takes place. Using roles as your primary security methodology will ensure future interoperability and easier administration.
Role definition is part of the initial application design, not final deployment. If you are writing business logic code and have not thought about roles, you are taking a huge risk in having to make major redesigns later. Take the time upfront to ambitiously study your business solution in terms of roles and how they will be handled by your implementation.
By appropriately mapping the security accounts to your roles, you will be able to control security in your application as it evolves. This can be done declaratively by setting permissions on objects, interfaces, or methods or programmatically by changing your logic in-code depending on the user.
How To
You create roles for a given COM+ application by adding them to the Roles folder in the Component Services MMC Snap-in. You can then add network groups and users to the roles as easily as you add permissions on a file.
Once you have determined the roles, you assign Windows NT groups (and users) that belong in them. You then add and remove roles to/from the appropriate objects, interfaces, and methods. The presence of a role for a certain object, interface, or method indicates access to it is granted for all Windows NT groups and users belonging to that role. Keep in mind that when an object has certain roles to it, its interfaces and methods automatically inherit those roles. If a Manager's role has access to the MoneyTransfer object, then the Manager's role will automatically have access to the interfaces and roles in the object.
You can also use the ObjectContext function IsCallerInRole to programmatically react to the user's identity—for example, to stop money transfers of more than $10,000 to anyone not a member of a 'Senior Account Managers' role.
References
Designing Roles Effectively
Using Role-Based Security
Authorizing Clients Using Roles
Configuring Role-based Security
Select the Right Security Granularity
A typical problem that hurts scalability is when identity granularity is too small. For example, do you need to have each specific end-user registered in your database (as an example of a secure resource) or is it enough to know a specific role or functional area to which this operation belongs?
In many cases, from the back end's point of view, an application rather than a specific user uses a resource. Having coarser security granularity will bring the following benefits:
- Simpler administration—the resource only manages a handful of user applications.
- More scalability—components running activities for different end users may share connections or take advantage of connection pooling.
However, this comes at a cost of less fine-grained auditing capabilities. While this may sound like a big cost, be realistic regarding your auditing plans and processes.
Try not to use separate SQL Server logins for every application user. Use different logins for different roles. Thus, rather than restricting or auditing users A and B and C, you will be setting database permissions on your roles, Managers, Clerks, Account Managers, and so on. This can be accomplished by using a different connection string depending on the roles to which the current user belongs.
You can use the following function to accomplish this task. This code makes a number of simple assumptions:
- Some roles will have specific SQL Server logins that want to be enforced.
- Some roles precede others. For example, if a user is both an Employee and a Manager, you probably want it to connect to the database with Manager access.
- The component has an array that may have been obtained from the object's constructor with a list of the roles to use in appropriate precedence. The last element in the list is the default connection.
- There is a set of UDLs with the same name as the roles on the same path as the DLL.
Public Function GetRoleConnectionString(RoleList As Variant) As String
Dim i As Integer
Dim oCtx As ObjectContext
Set oCtx = GetObjectContext
For i = LBound(RoleList) To UBound(RoleList) - 1
If oCtx.IsCallerInRole(RoleList(i)) Then Exit For
Next i
'We build a connection string out of the UDL name by
'adding FILE, the path and the extension
GetRoleConnectionString = "FILE Name=" & App.path & "\" &_
RoleList(i) & ".UDL"
Set oCtx = Nothing
End Function
This function may be used the following way:
' Assuming we have a comma-delimited list of special roles
' e.g.: "Managers,Employees,HelpDesk,DefaultUser"
' that may have been obtained from the constructor string for the object…
'Declare a place to put our array of roles
Dim vRoles As Variant
'As an example, create the array from a comma-delimited string…
'you may have obtained this string from the object constructor or the SPM.
'Note the precedence of the role list – a user in both the Managers
'and HelpDesk roles
'will get the Managers login.
vRoles = Split("Managers,Employees,HelpDesk,DefaultUser" , ",")
'Open the connection!
oADODBConnection.Open GetRoleConnectionString(vRoles)
Do Not Use Delegate for Integrated Security Database Logins
As mentioned in the Select the Right Security Granularity section, specifying resource logins on a per-user basis is usually overkill. However, if you need this fine control, COM+ has new functionality that allows COM+ components running as a certain user to impersonate that user when accessing certain resources. This simplifies the component logic since there is no need to do an artificial caller id-login association.
All COM+ applications have a setting for Impersonation Level. This setting will determine to what level the component will act as being the calling user. The highest setting, Delegate, allows your component to access remote resources appearing as its current caller. This allows you to leverage SQL Server integrated security, specifying SQL Server NT logins for your application users.
The main benefit Delegate impersonation brings is that the resource may manage its own security at a fine granularity. For example, the DBA can manage SQL Server security and auditing at a per-user level.
The drawbacks of Delegate impersonation to login to databases lies in that connections cannot be pooled, since they are opened for a specific user. This will drastically increase the connections required to work and will cause delays when connecting/disconnecting to the database.
If you are using SQL Server Integrated Security, then you may evaluate using lower impersonation levels that allow you to have a coarser granularity for the logins. You can also use the code sample in Select the Right Security Granularity to have a flexible compromise between the "one user-one login" and the "all users-one login" approach.
Distribute Active Directory and Application Server Functionality
You should avoid making application servers out of machines hosting Active Directory. These machines are usually Domain Controllers (DCs) and there will be heavy competition for network resources among the services you host on these machines. In addition, memory resources consumed by a domain controller can be quite high, leaving little resources for your application.
More Information
Application servers must be able to respond consistently to varying user loads and server state scenarios. Users expect the same response to their request throughout the workday. Any concurrent DC duties will impact this consistent performance and lead to end user dissatisfaction with your solution. The role of a Domain Controller machine is different enough from that of an application server that they each merit their own dedicated machine.
How To
As a rule, try to isolate the resource usage and reduce the shared failure point between your services. Putting two stressful and important tasks on a single machine does not meet your ultimate objective of high availability, reliability, manageability, or failure isolation.
Make Sure that Authentication Is Possible if Required
Authentication is the act of positively identifying the user based upon the credentials presented to the authenticating authority. The server machine does this by contacting a Domain Controller to request acknowledgement of the calling identity. There are many levels of DCOM authentication ranging from None, in which the server does not attempt to validate the calling user, to Privacy, in which the network packets are encrypted and data integrity and privacy are guaranteed.
The level of authentication for a communication is determined by a negotiation between the client and the server machines. The higher of both settings is used. In other words, the server attempts to enforce the stricter of the client and server settings should they differ.
More Information
When a call or object creation request comes in to a server for a DCOM connection with an authentication level higher than None, the server must verify the identity of the caller with a DC. However, if no DCs are available, or if the call comes from a domain with which there is no trust, this cannot be accomplished, and the call will fail with the message Access Denied.
In this case, you must either change the network or trust configuration, or decrease the authentication level. At some point, you can decrease the authentication level to the point where any credentials are accepted by the Service Control Manger (SCM).
How To
To set the authentication level on the server, open the COM+ Application Property Sheet and select the Authentication Level from the Security tab. Shutdown your package after changing this setting to get it enforced.
On the client, the authentication level is set for both the application and the machine level. In a typical Windows NT 4.0, or Windows 9x machine, you must open DCOMCNFG and change the default authentication level and the application's authentication level. Remember that the effective level enforced by the server will be the highest of both.
If you want to use your application from a Windows 9x client that does not log on to the domain, you will need to set the authentication level to None for the client computer and the server COM+ application. You can do so in the Security tab of the application's properties.
References
Setting COM+ Application Authentication
Tune Your Application Timeout
COM+ server applications have a timeout setting that you set to schedule an automatic shut down after the application has been sitting idle for a specified time. Every COM+ server application runs as a distinct DLLHOST.EXE process on a machine. With every process there are certain resources allocated. In many cases, application processes fragment their private heap of memory or even leak memory if they use libraries or components not designed to run in servers.
When the process is shut down, this pool of memory is returned to the operating system to be reallocated for another process. Your application can get a fresh start on life and receive the merits of a fresh pool of memory whenever it restarts. For most sites, having an automatic shutdown is not possible due to the constant and frequent hits. However, when you do have a choice, perform this proactive maintenance action.
You may have a decrease in usage frequency on weekends, late at night, or some other moment. Tune your timeout to happen in these usage valleys.
More Information
Some problems regarding server applications, such as memory leaks, handle leaks, state expiration, and so on, are wiped out when their process closes. Although this won't cause your problems to go away and they should be addressed immediately, you might sidestep the sometimes too harsh symptoms of resource exhaustion by specifying a proactive shutdown at a low-impact moment.
The only impact that you will see is that your database connection pool will be reset and that the first user to require the application since the shutdown will experience a slight delay due to the time required to start the process again.
How To
To set the timeout value, open the Component Services snap-in in Administrative Tools, then open the COM+ Application Property Sheet and click on the Advanced tab. Then set the value as shown in Figure 7.
.gif)
Figure 7. Setting an application timeout
Remember that if a client holds a reference to a server object without using it, it won't prevent the shutdown from happening and the client will need to re-acquire the connection.
The application must be activated on the server. Library applications don't have a timeout since they don't have their own process.
References
Types of COM+ Applications
Install (not Import) Your Components into COM+
When adding components to a COM+ application through the Component Services MMC Snap-in you have one of two choices:
- Dragging and dropping the DLL file into the components list.
- Right clicking under the Components folder for the package, selecting New, and choosing Import objects already registered or Install new components.
If you use this second method, use Install as depicted in Figure 8.
.gif)
Figure 8. The Component Installation dialog box
More Information
When installing a component, MTS will query the DLL for specific information regarding the objects, interfaces, and their attributes. It will also configure the component taking into account all this information.
When importing, however, MTS will only change the local registration information to point to MTS, so the objects get instantiated within it. However, it does not validate that the component can actually be installed in MTS (not applicable in Visual Basic) and perhaps more critical, it does not query the DLL for all the classes' attributes. Therefore, if a class module was marked in Visual Basic as requiring transactions, it will appear as not supporting transactions if imported into MTS.
In addition, upgrading your MTS server to Windows 2000 and COM+ will make migrating the MTS packages to COM+ applications a lot easier if the components are installed and not imported.
How To
In the Add Component Wizard, always choose Install and then select the DLL, or drag and drop the DLL from Windows Explorer to the Components folder of the package.
References
Installing New Components
Importing Components
Make Sure There Is Good RPC Connectivity Between COM+ and SQL Server Machines
When there are separate application and database server machines connected in a network, all transactions are coordinated by the Distributed Transaction Coordinator (DTC) services on both machines. These DTC services require Remote Procedure Call (RPC) communication with each other, in a connection-oriented protocol. This might be ncacn_ip_tcp, ncacn_spx, or ncacn_nb_nb. They also refer to each other using host names instead of IP addresses, so you have to make sure that name resolution is working correctly in both directions.
More Information
The DTCs in different computers coordinate transactions amongst each other and their respective local resource managers. To communicate, they need RPC connectivity. This implies:
- Correct ports are available for RPC (if there is a firewall in between).
- Correct name resolution is working in both directions.
Since the DTC requires reliable communications, it needs a transport that is connection-oriented. For example, UDP/IP will not suffice, but TCP/IP will. These are identified by ncacn_ prefixed RPC transports.
How To
You must make sure both computers can ping each other by name. If you have a firewall, make sure to read the RPC and firewall documentation. You need to open ports 135 plus a certain range (e.g. 1100 to 1130) in both directions, and configure your computers to use this range.
To diagnose communication problems you might use RPCPing, a utility that lets you test RPC connectivity. When using RPCPing, make sure to look for the transports listed above by selecting Endpoint Search on the client-side of the pinged application. Note however, that the utility uses a specific port to test connectivity, which is not very faithful to DTC behavior. It is, however, a significant test.
More tools will be posted in the Microsoft Knowledge Base as they become available and have been adequately tested.
References
XCLN: How to use RPCPing to Test RPC Communication (Q167260)
Use Terminal Services as a Remote Administration Tool
You can configure Microsoft Terminal Server on a Windows 2000 server so that remote administration is made easier. Terminal Server can also be configured specifically for this task so that the terminal management does not affect the quality of service of the server. Terminal Services can also be used to control another user's session, enabling joint-administration and helpdesk scenarios.
Using Terminal Services for Remote Administration of the Windows 2000 Server Family
How to Use the Terminal Services Remote Control Feature (Q232792)
Use TCP/IP Instead of Named Pipes to Connect to SQL Server
There are several ways to connect to SQL Server, the common ones being TCP/IP, Named Pipes, and multiprotocol RPC.
More Information
Using TCP/IP to connect to SQL Server will give you the following benefits:
- Simpler connectivity configuration, even over a firewall.
- You will not have the security side effects of using Named Pipes across the network (security issues other than SQL Server access control).
- You will have better performance at higher volumes and more scalability.
Looking ahead, you may want to evaluate the use of XML on HTTP as your database protocol. This will become available with SQL Server 2000, which is still in beta. As more information becomes available and we see successful implementations, this document will be updated to convey the best practices.
How To
The protocol choice may be configured from the SQL Servers Client Network Utility, or by specifying the desired protocol in the connection string. The SQL Server 7.0 default is usually named Pipes, so you might want to verify this configuration after installation.
References
HOWTO: Change SQL Server Default Network Library Without Using Client Network Utility (Q250550)
INF: ODBC SQL Server Connection Parameters (Q137635)