You can control who can edit each field by making small changes to the Velocity template files used to display fields in the Edit Issue screen.
One of the points of pain with JIRA is trying to control who can edit particular fields of an issue, as discussed in JRA-1330. Various suggestions have been made there, such as using a workflow, but the page How to create a new Custom Field Type gave me the idea of simply changing the velocity template that is used to display a field to control who can edit the field's values. This approach also provides enough flexibility to make other changes such as who is permitted read the contents of a field.
Decide which field you want to control, e.g. Fix Versions
Find the template that is used to generate that field in the Edit Issue screen. The template is probably one of the files atlassian-jira/WEB-INF/classes/templates/jira/issue/field/*-edit.vm, e.g. versions-edit.vm in this case
If you have the source code, then you can confirm exactly which template is used by looking in jira/src/java/com/atlassian/jira/issue/fields for the field type you are interested in.
Note that some templates are used by more than one field, e.g. the versions-edit.vm is used for both the Affects Versions and Fix Versions fields.
Find the field id of the field you want to control, e.g. for Fix Versions the field id is fixVersions. I actually found this out by simply tweaking the template to print out the $field.id, but it's really defined in atlassian-jira-enterprise-3.8-source/jira/src/java/com/atlassian/jira/issue/IIssueFieldConstants.java.
Make the changes and restart JIRA.
This example shows the changes made to versions-edit.vm to control who can edit the Fix Versions field.
<!-- By default, the fields are writeable -->
#set ($readonly = "no")
#if ($field.id == "fixVersions")
<!-- This example is restricting who can change the Fix Version to
members of the fix-version-writers group -->
#set ($readonly = "no")
#set ($readonly = "yes")
The following line is part of the original template
#if ($versions && !$versions.empty)
but these are the lines that change what is displayed. A "break" command would be useful in Velocity.
#if ($readonly == "yes")
<!-- Display the field value -->
#foreach ($cv in $currentVersions)
#foreach ($version in $versions)
#if ($cv == $version.key)
<!-- The Fix Version has not been set -->
All the other lines in this file are unchanged except for the closing #end line